Elasticsearch 操作
Elasticsearch 操作工具 VS Code 插件安装及使用
Elasticsearch DSL
Elasticsearch DSL(Domain Specific Language特定领域语言)以JSON请求体的形式出现,提供丰富且灵活的查询语言叫做DSL查询(Query DSL),它允许你构建更加复杂、强大的查询
字段类型
字段类型介绍
在 Elasticsearch
中,每一个字段都有一个类型(type),以下为 Elasticsearch
中可以使用的类型
分类 | 类型名称 | 说明 |
---|---|---|
简单类型 | text | 需要进行全文检索的字段,通常使用text类型来对应邮件的正文、产品描述或者短文等非结构化文本数据。分词器先会将文本进行分词转换为词条列表。将来就可以基于词条来进行检索了。文本字段不能用户排序、也很少用户聚合计算 |
keyword | 使用keyword来对应结构化的数据,如ID、电子邮件地址、主机名、状态代码、邮政编码或标签。可以使用keyword来进行排序或聚合计算 注意:keyword是不能进行分词的 | |
date | 保存格式化的日期数据,例如:2015-01-01或者2015/01/01 12:10:30。在Elasticsearch中,日期都将以字符串方式展示。可以给date指定格式:”format”: “yyyy-MM-dd HH:mm:ss” | |
long/integer/short/byte | 64位整数/32位整数/16位整数/8位整数 | |
double/float/half_float | 64位双精度浮点/32位单精度浮点/16位半进度浮点 | |
boolean | “true”/”false” | |
ip | IPV4(192.168.1.110)/IPV6(192.168.0.0/16) | |
JSON分层嵌套类型 | object | 用于保存JSON对象 |
nested | 用于保存JSON数组 | |
特殊类型 | geo_point | 用于保存经纬度坐标 |
geo_shape | 用于保存地图上的多边形坐标 |
索引操作
注意:判断字段类型是使用text、还是keyword,主要就看是否需要分词
创建带有映射的索引
# 格式
PUT /my-index
{
"mapping": {
"properties": {
"employee-id": {
"type": "keyword",
"index": false
}
}
}
}
# 示例
PUT /job_idx
{
"mappings": {
"properties" : {
"area": { "type": "text", "store": true},
"exp": { "type": "text", "store": true},
"edu": { "type": "keyword", "store": true},
"salary": { "type": "keyword", "store": true},
"job_type": { "type": "keyword", "store": true},
"cmp": { "type": "text", "store": true},
"pv": { "type": "keyword", "store": true},
"title": { "type": "text", "store": true},
"jd": { "type": "text", "store": true}
}
}
}
查看指定的索引
// 格式
GET /索引名称/_mapping
// 示例
GET /job_idx/_mapping
查看所有的索引
GET _cat/indices
查看索引的状态
// 查看 job_idx 索引的状态
GET _cat/indices?index=job_idx
删除指定的索引
// 格式
delete /索引名称
// 示例
delete /job_idx
分片、副本
创建索引并指定分片和副本
创建索引,并指定该索引有 3 个分片和 2 个副本
# 格式
PUT /my-index
{
"mapping": {
"properties": {
"employee-id": {
"type": "keyword",
"index": false
}
}
},
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2
}
}
查看分片和副本
GET /_cat/indices?v
分词器操作
指定分词器
// 指定分词器为标准分词器
post _analyze
{
"analyzer":"standard",
"text":"我爱你中国"
}
// 指定分词器为 IK分词器
post _analyze
{
"analyzer":"ik_max_word",
"text":"我爱你中国"
}
创建索引并指定分词器
PUT /job_idx
{
"mappings": {
"properties" : {
"area": { "type": "text", "store": true, "analyzer": "ik_max_word"},
"exp": { "type": "text", "store": true, "analyzer": "ik_max_word"},
"edu": { "type": "keyword", "store": true},
"salary": { "type": "keyword", "store": true},
"job_type": { "type": "keyword", "store": true},
"cmp": { "type": "text", "store": true, "analyzer": "ik_max_word"},
"pv": { "type": "keyword", "store": true},
"title": { "type": "text", "store": true, "analyzer": "ik_max_word"},
"jd": { "type": "text", "store": true, "analyzer": "ik_max_word"}
}
}
}
数据操作(增、删、查、改)
添加数据
在 Elasticsearch 中,每一个文档都有唯一的 ID。也是使用 JSON 格式来描述数据,例如
// 如果在 customer 中,不存在 ID 为 1 的文档,Elasticsearch 会自动创建
PUT /customer/_doc/1{
"name": "John Doe"}
查看数据
① 使用 ES-head 插件浏览数据
② 使用 DSL
查看
get /job_idx/_doc/29097
修改数据
// 将 doc_id 为 29097 的 salary 由 '6-8千/月' 修改为 '15-20千/月'
POST /job_idx/_update/29097
{
"doc": {
"salary": "15-20千/月"
}
}
删除数据
// 将 索引 job_idx 下 doc_id 为 29097 的数据删除
DELETE /job_idx/_doc/29097
数据批量导入
Elasticsearch 中自带的 bulk 接口可以实现数据导入
① 将文件上传至 ElasticSearch
服务器
② 执行导入命令
curl -H "Content-Type: application/json" -XPOST "node1:9200/job_idx/_bulk?pretty&refresh" --data-binary "@/opt/server/job_info.json"
数据查询
根据文档 ID 查询数据
// 格式
GET /索引名称/_search
{
"query": {
"ids": {
"values": ["46313"]
}
}
}
// 示例:查询 job_idx 索引下的文档 id 为 46313 的数据
GET /job_idx/_search
{
"query": {
"ids": {
"values": ["46313"]
}
}
}
根据关键字查询数据
// 第一种:检索 jd 字段中包含 '销售' 的数据
GET /job_idx/_search
{
"query": {
"match": {
"jd": "销售"
}
}
}
// 第二种:检索多个字段中包含 '销售' 的数据
GET /job_idx/_search
{
"query": {
"multi_match": {
"query": "销售",
"fields": ["title", "jd"]
}
}
}
分页查询(from…size…)
指定页码、并指定每页显示多少条数据,然后 Elasticsearch 返回对应页码的数据
// from = (page – 1) * size
GET /job_idx/_search
{
"from": 0,
"size": 5,
"query": {
"multi_match": {
"query": "销售",
"fields": ["title", "jd"]
}
}
}
分页查询(scroll)
使用 from 和 size 方式,查询超过 5W
的数据,会出现性能问题。Elasticsearch 做了一个限制,不允许查询的是 1W 条以后的数据。如果要查询 1W 条以后的数据,需要使用 Elasticsearch 中提供的 scroll 游标来查询
在进行大量分页时,每次分页都需要将要查询的数据进行重新排序,这样非常浪费性能。使用 scroll 是将要用的数据一次性排序好,然后分批取出。性能要比 from + size 好得多。使用scroll查询后,排序后的数据会保持一定的时间,后续的分页查询都从该快照取数据即可。
① 第一次使用 scroll
第一次查询后,得到了 “_scroll_id”: “DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAAYWckc4eVVyUFJRYU80YWNONG1LWnctQQ==” ,在后续的 1 分钟内,可以直接通过这个 _scroll_id
去查询数据
// scroll = 1m 保持查询结果 1min
GET /job_idx/_search?scroll=1m
{
"query": {
"multi_match": {
"query": "销售",
"fields": ["title", "jd"]
}
},
"size": 100
}
② 第二次使用 scroll
直接使用第一次得到的 _scroll_id
查询
GET _search/scroll?scroll=1m
{
"scroll_id": "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAAYWckc4eVVyUFJRYU80YWNONG1LWnctQQ=="
}
Elasticsearch SQL
Elasticsearch SQL 的缺陷
不支持JOIN、不支持较复杂的子查询。所以,有一些相对复杂一些的功能,还得借助于DSL方式来实现
SQL 与 Elasticsearch 对应关系
SQL | Elasticsearch |
---|---|
column(列) | field(字段) |
row(行) | document(文档) |
table(表) | index(索引) |
schema(模式) | N/A |
database(数据库) | Elasticsearch集群实例 |
Elasticsearch SQL 语法
-- 目前 FROM 只支持一个表
SELECT select_expr [, ...]
[ FROM table_name ]
[ WHERE condition ]
[ GROUP BY grouping_element [, ...] ]
[ HAVING condition]
[ ORDER BY expression [ ASC | DESC ] [, ...] ]
[ LIMIT [ count ] ]
[ PIVOT ( aggregation_expr FOR column IN ( value [ [ AS ] alias ] [, ...] ) ) ]
格式化返回数据
格式化类型
格式 | 描述 |
---|---|
csv | 逗号分隔符 |
json | JSON格式 |
tsv | 制表符分隔符 |
txt | 类cli表示 |
yaml | YAML人类可读的格式 |
格式化语法
// format 为指定的类型
GET /_sql?format=txt
{
"query": "SELECT * FROM job_idx limit 1"
}
SQL 转换为 DSL
GET /_sql/translate
{
"query": "SELECT * FROM job_idx limit 1"
}
Scroll分页查询
游标查询
① Scroll 第一次分页查询
// 格式
GET /_sql?format=json
{
"query": "SELECT * FROM 索引",
"fetch_size": 10
}
// 示例:分页查询索引为 job_idx 的数据
GET /_sql?format=json
{
"query": "SELECT * FROM job_idx",
"fetch_size": 10
}
② Scroll 第二次分页查询 (查询时使用 Scroll ID)
GET /_sql?format=json
{
"cursor": "Scroll ID"
}
清除游标
POST /_sql/close
{
"cursor": "Scroll ID"
}
全文检索
MATCH 函数介绍
// field_exp:匹配字段
// constant_exp:匹配常量表达式
MATCH(
field_exp,
constant_exp
[, options])
)
// 示例:匹配在 title 字段中包含 '销售' 的数据
MATCH(title, '销售')
全文检索实现
// 示例:搜索在 title 和 jd 字段中包含 '销售' 的数据
GET /_sql?format=txt
{
"query": "select * from job_idx where MATCH(title, '销售') or MATCH(jd, '销售') limit 10"
}