DSL 搜索
ES 使用 queryString
形式根据搜索词对索引表的文档进行检索:
GET /{indexName}/_doc/_search?q={fieldName1}:{searchTxt1}&q={fieldName2}:{searchTxt2}..
但这种 queryString
的形式查询数据只适合一些简单查询的场景,一旦参数多了就难以进行构建(需要添加分页、过滤等功能),所以多数情况下使用 DSL Domain Specific Language
进行查询更好,因为它基于 JSON 格式的数据查询,这样的可读性会更好,有利于复杂查询。
1 DSL 语法
1.1 基本搜索
match_all
关键字,表示 在索引中查询所有文档(上一篇文章有queryString
查询的做法)
-
_source
关键字填充需要搜索的字段名 -
from
和size
:默认的 ES 只显示10条数据,此时可以使用分页显示,from
是表示从起始索引,size
表示一页显示的个数
POST /{indexName}/_doc/_search
{
"query": {
"match_all": {}
},
"_source": [{fieldName1}, {fieldName2}...],
"from": 1,
"size": 5
}
match
关键字,将 搜索内容进行分词后搜索
-
match
关键字默认的operator
属性是or
,即搜索内容分词后,只要存在一个词语匹配就展示结果,设置为and
后,搜索内容分词后,都要满足词语匹配 -
minimum_should_match
:最低匹配精度,比如说最低匹配精度为70%
,而搜索内容分词后有10
个词语,则文档必须要有10*0.7=7
个词语匹配才会符合显示需求。
POST /{indexName}/_doc/_search
// 默认 operator 为 or
{
"query": {
"match": {
{fieldName}: {searchTxt}
}
}
}
// 设置 operator 为 true
{
"query": {
"match": {
{fieldName}: {
"query": {searchTxt},
"operator": "and"
}
}
}
}
// 最低匹配精度
{
"query": {
"match": {
{fieldName}: {
"query": {searchTxt},
"minimum_should_match": {minimum_should_match}
}
}
}
}
multi_match
关键字,满足使用match
模式在多个字段属性中进行查询的需求
-
boost
权重,多字段属性查询时,可为某些字段属性设置权重,权重越高,文档相关性得分就越高,如下{fieldName2}^{weight}
举例:"desc^10"
表示desc
字段属性搜素提升10
倍相关性,即如果其他字段没有设置权重,用户搜索时会以desc
为主
POST /{indexName}/_doc/_search
{
"query": {
"multi_match": {
"query": {searchTxt},
"fields": [{fieldName1}, {fieldName2}...]
}
}
}
// 设置权重
{
"query": {
"multi_match": {
"query": {searchTxt},
"fields": [{fieldName1}, {fieldName2}^{weight}...]
}
}
}
-
match_phrase
关键字,搜索内容的分词结果必须在文档分词中都包含,且顺序必须相同,而且必须连续(词与词之间必须紧贴在一起),除非设置了slop
属性,允许词语之间跳过的文字数量
POST /{indexName}/_doc/_search
{
"query": {
"match_phrase": {
"desc": {
"query": {searchTxt},
"slop": {slopNum}
}
}
}
}
-
term
关键字与terms
关键字,将 搜索内容作为一整个关键词去搜索,而不是进行分词后搜索,同时terms
支持多个词语匹配检索
POST /{indexName}/_doc/_search
// term
{
"query": {
"term": {
{fieldName2}: {searchTxt2},
}
}
}
// terms
{
"query": {
"terms": {
{fieldName1}: [{searchTxt1}, {searchTxt2}...]
}
}
}
-
prefix
关键字,根据前缀去查询
POST /{indexName}/_doc/_search
{
"query": {
"prefix": {
// {prefixTxt} 作为前缀
{fieldName}: {prefixTxt},
}
}
}
-
fuzzy
关键字,在用户进行搜索时可能出现打错字的现象,搜索引擎会自动纠正,然后尝试匹配数据
POST /{indexName}/_doc/_search
{
"query": {
"fuzzy": {
{fieldName}: {errorWord}
}
}
}
-
ids
关键字,根据主键 ID 搜索
POST /{indexName}/_doc/_search
{
"query": {
"ids": {
"type": "_doc",
"values": [{id1}, {id2}...]
}
}
}
1.2 布尔查询
- 布尔查询(多重组合查询)
-
must
:查询必须匹配搜索条件,类似于 SQL 语句的and
-
should
:查询匹配满足一个以上条件,类似于 SQL 语句的or
-
must_not
:不匹配搜索条件,一个都不要满足 - 有时候,搜索同一个文档字段属性,希望
搜索内容分词A
比搜索内容分词B
权重更高可以使用should
模式并设置boost
权重属性
POST /{indexName}/_doc/_search
// 使用 must 举例
{
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": {searchTxt1},
"fields": [{fieldName1}, {fieldName2}..]
}
},
{
"term": {
{fieldName3}: {searchTxt2}
}
},
{
"term": {
{fieldName4}: {searchTxt3}
}
},
...
}
]
}
}
}
// 同时使用 must,should,must_not 也是可以的
{
"query": {
"bool": {
"must": [
...
]
"should": [
...
]
"must_not": [
...
]
}
}
}
// 使用 should 时,可以添加权重,举例
{
"query": {
"bool": {
"should": [
{
"match": {
"desc": {
"query": "律师",
"boost": 18
}
}
},
{
"match": {
"desc": {
"query": "进修",
"boost": 2
}
}
}
]
}
}
}
1.3 过滤器
对搜索出来的结果进行数据过滤(即查询后,对结果数据的筛选),不会到 ES 库里去搜,不会计算文档的相关度分数,所以过滤的性能会比较高,过滤器可以和全文搜索结合在一起使用。post_filter
元素和上述的 query
元素一样,都是顶层元素,但 post_filter
不会计算数据的匹配度相关性分数,不会据分数排序。
举例:
POST /{indexName}/_doc/_search
// term
{
"query": {
"term": {
{fieldName2}: {searchTxt2},
}
},
// money 字段属性需要大于 60,小于 100
"post_filter": {
"range": {
"money": {
"gt": 60,
"lt": 100
}
}
}
}
1.4 排序
sort
元素和上述的 query
元素一样,都是顶层元素。
POST /{indexName}/_doc/_search
// term
{
"query": {
"term": {
{fieldName2}: {searchTxt2},
}
},
"sort": [
{
{fieldName1}: "desc"
},
{
{fieldName2}: "asc"
}
...
]
}
对文本排序,由于文本会被分词,所以排序的时候就会不知道用哪个分词后的内容去进行排序,所以需要在一开始设置文档字段的时候额外添加一个附属属性 keyword
,用于排序:
POST /{indexName}/_mapping
{
"properties": {
{fieldName}: {
"type": {typeName},
"analyzer": {analyzerName},
// 设置 keyword
"fields": {
"keyword": {
"type": "keyword"
}
}
}
}
}
1.5 关键字高亮显示
POST /{indexName}/_doc/_search
// term
{
"query": {
"term": {
{fieldName}: {searchTxt},
},
"term": {
{fieldName2}: {searchTxt2},
}
},
// 搜索词前后添加 span 标签
"highlight": {
"pre_tags": ["<span class="highlight">"],
"post_tags": ["</span>"],
"fields": {
{fieldName}:{},
{fieldName2}:{}
}
}
}
2 深度分页
深度分页其实就是指搜索的深浅度,比如第 10000
页,ES 在获取第 9999
条到 10009
条数据的时候,假如设置了多个主分片,那么它会从每个分片中拿出 10009
条数据集合在一起,再对这些汇总数据进行排序处理,最后获取对应的 10
数据,这样一来就会有性能的问题,ES 默认是不支持操作一万条数据以上的分页查询,而我们也应该避免深度分页操作(限制分页页数)
通过设置 index_max_result_window
来突破限制
PUT /{indexName}/_settings
{
"index_max_result_window": "20000"
}
2.1 scroll
滚动搜索
一次性查询一万加的数据,往往会造成性能影响,因为数据量太多,这时候就可以使用滚动搜索。
滚动搜索可以先查询出一些数据,然后再接着依次往下查询,查询的时候会返回一个滚动 ID,相当于一个 锚标记
,接下来的每次查询都需要携带上一次返回的 锚标记
,值得注意的是,如果有数据变更,搜索出来的数据也只是旧版本的数据。
第一次滚动查询:
// scroll=1m 相当于是一个session会话时间,搜索保持上下文1分钟
POST /{indexName}/_search?scroll=1m
{
"query": {
"match_all": {}
},
"sort": ["_doc"],
"size": 5 // 设置单页查询数量
}
后续查询:
POST /_search/scroll
{
"scroll": "1m", //相当于是一个session会话时间,搜索保持上下文1分钟
"scroll_id": {scroll_id}
}
3 批量操作
bulk 操作和以往的普通的请求格式有区别,它不能支持格式化 json,它的发送数据格式是:
{action:{metadata}}\n
{request body}\n
{action:{metadata}}\n
{request body}\n
...
{action:{metadata}}
代表批量操作的类型,不同操作类型之间是可以混合在同一请求中使用的
-
create
:新增,如果文档不存在,就创建他,存在则会报错,但不影响其它操作 -
index
:创建或替换一个现有的文档 -
update
:部分更新文档 -
delete
:删除一个文档
-
\n
即是回车符(不是填写\n
进去请求体中,而是直接按回车键即可),每行结尾必须填写的规范(包括最后一行) -
{request body}
:增和改操作的内容,删除操作无需携带
metadata
中需要指定要操作的文档的 _index
(索引表表名)、_type
(固定值为 _doc
)和 _id
,其中 _index
和 _type
可以直接在 url
中指定。
-
create
操作
POST /_bulk
// 或者 /{indexName}/_doc/_bulk 这样指定url的话,下方 metaData 就无需声明 _index 和 _type
{"create":{"_index":{indexName1},"_type":"_doc","_id":{id1}}}
{{fieldName1}: {value1}, {fieldName2}: {value2}}
{"create":{"_index":{indexName1},"_type":"_doc","_id":{id2}}}
{{fieldName1}: {value3}, {fieldName2}: {value4}}
{"create":{"_index":{indexName2},"_type":"_doc","_id":{id3}}}
{{fieldName3}: {value5}, {fieldName4}: {value6}}
-
index
操作,创建或替换一个现有的文档
POST /{indexName}/_doc/_bulk
{"index":{"_id":{id1}}}
{{fieldName1}: {value1}, {fieldName2}: {value2}}
{"index":{"_id":{id2}}}
{{fieldName1}: {value3}, {fieldName2}: {value4}}
-
update
操作,创建或替换一个现有的文档
POST /{indexName}/_doc/_bulk
{"update":{"_id":{id1}}}
{"doc":{{fieldName1}: {value1}, {fieldName2}: {value2}}}
{"index":{"_id":{id2}}}
{"doc":{{fieldName1}: {value3}, {fieldName2}: {value4}}}
-
delete
操作,创建或替换一个现有的文档
POST /{indexName}/_doc/_bulk
{"delete":{"_id":{id1}}}
{"delete":{"_id":{id2}}}