Elasticsearch 7提供了多种检索文档的方式,我们可以通过Restful API的方式来搜索索引中的文档。Elasticsearch的搜索可以分为以下几个类型:
- 全文搜索
- 词项搜索
- 复合搜索
- 嵌套搜索
- 位置搜索
- 特殊搜索
本文例子采用测试文档库shakespeare,下载链接https://www.elastic.co/guide/en/kibana/7.2/tutorial-build-dashboard.html 。
1 全文搜索
全文搜索通常用于搜索文本字段,需要用户提供关键字来完成。
1.1 match搜索
match搜索会对用户给出的关键词进行解析,首先会将其进行分词处理,分词后查询语句中的任意一个词项被匹配,文档就会检索到。其子参数包含:
query
(必填):搜索关键文本analyzer
(可选):分词器,用于将query
中的文本转换为一个个词项fuzziness
(可选):使用编辑距离技术进行模糊匹配prefix_length
:模糊匹配的起始单词数operator
(默认为OR):布尔逻辑,用来解释query
中的词项,可选的参数有OR、ANDminimum_should_match
(可选):返回的文档需要匹配的最小子串数
示例:
GET /shakespeare/_search
{
"query": {
"match": {
"text_entry": {
"query": "apple eye",
"operator": "and"
}
}
}
}
查询包含text_entry
字段中包含单词apple和eye的文档
1.2 match_phrase搜索
match_phrase搜索会首先把query
进行分词处理,分词器可以自定义,同时文档还需满足以下条件才能被匹配:
- 分词后所有词项都要出现在该字段中
- 字段中所有的词项顺序要一致
如果将上述示例改为match_phrase,那么只有eye在apple后面的文档才可以被搜索到。
1.3 match_phrase_prefix搜索
和match_phrase搜索类似,只不过match_phrase_prefix支持词项的前缀匹配,例如:
GET /shakespeare/_search
{
"query": {
"match_phrase_prefix": {
"text_entry": {
"query": "app"
}
}
}
}
那么只会查找出某个词项的前缀为app的文档。
1.4 multi_match搜索
multi_match搜索是match的升级版,可以用于搜索多个字段,例如:
GET /shakespeare/_search
{
"query": {
"multi_match": {
"query": "apple",
"fields": ["text_entry", "speaker"]
}
}
}
上述查询语句会在text_entry
和speaker
字段中查询包含单词apple的文档
1.5 match_bool_prefix搜索
match_bool_prefix搜索于Elasticsearch 7.0推出,它将输入的文本通过指定的分词器来处理多个term
,然后基于这些term
进行bool query,除了最后一个term
使用前缀查询,其它都是使用term_query。
GET /shakespeare/_search
{
"query": {
"match_bool_prefix": {
"query": "away as nim",
}
}
}
上述示例相当于查询包含单词away、as,并且有单词以nim开头的文档。
2 词项搜索
全文搜索在查询前会分析query
字符串,而词项搜索一般用于对存储的词项进行精确搜索,通常用于一些结构化数据,例如数字、枚举类型、日期类型等。
2.1 term
最基本的词项搜索,用于检索出某个text
字段中包含指定单词的文档。例如:
GET /shakespeare/_search
{
"query": {
"term": {
"text_entry": {
"value": "apple",
"boost": 1.0
}
}
}
}
上述请求可以查找出text_entry
字段中包含单词apple的文档。
value
参数为需要查找的词项;
boost
用来减少或增加相关性系数,默认为1.0,大于1.0会增加其相关性,小于1.0会减少其相关性。
2.2 terms
terms
可以用来查找text
字段中包含一个或多个指定单词的文档,例如:
GET /shakespeare/_search
{
"query": {
"terms": {
"text_entry": [
"eye","apple"
]
}
}
}
上述请求会查找出text_entry
字段中满足以下要求的文档:
- 包含单词eye,不包含单词apple
- 包含单词apple,不包含单词eye
- 包含单词eye和apple
同样,terms也可以使用boost
来减少或增加相关性系数。
2.3 regexp
regexp
检索可以查找出包含满足正则表达式单词的文档,例如:
GET /shakespeare/_search
{
"query": {
"regexp": {
"text_entry": "pa.*"
}
}
}
上述请求会查找出text_entry
字段中包含以pa开头的单词的文档。
需要注意regexp
检索不支持包含^
(行的开头)或$
(行的结尾)的正则表达式。
regexp
检索还支持以下几个参数:
flags
:启用正则表达式可选运算符max_determinized_states
:查询所需的最大自动机状态数,用于限制过于复杂的正则表达式,默认10000。
2.4 prefix
prefix
检索可以查找出包含指定字符串开头的单词的文档,例如:
GET /shakespeare/_search
{
"query": {
"prefix": {
"text_entry": {
"value": "par"
}
}
}
}
上述请求会查找出包含以par开头的单词的文档。
2.5 range
range
检索可以用于查询指定字段中在指定范围内的文档,例如:
GET /shakespeare/_search
{
"query": {
"range": {
"line_id": {
"gte": 160,
"lte": 170
}
}
}
}
上述请求可以查找出line_id
字段大于等于160,小于等于170的文档。此外还有gt
和lt
,用于表示大于和小于符号。
2.6 wildcard
wildcard
检索用于单词的通配符检索,相当于一个简化版本的regexp
检索,?
用于匹配一个任意字符,*
号用于匹配0个或者多个任意字符,相当于正则的.*
。例如:
GET /shakespeare/_search
{
"query": {
"wildcard": {
"text_entry": {
"value": "pre*"
}
}
}
}
上述请求可以查找出text_entry
字段中包含以pre开头的单词的文档。此外wildcard
也支持boost
参数,作用类似。
2.7 fuzzy
fuzzy
检索用于词项的近似检索,例如applx
可以检索出包含apple
单词的文档,两个单词的相似度通过编辑距离算法(Levenshtein)确定。例如:
GET /shakespeare/_search
{
"query": {
"fuzzy": {
"text_entry": "applx"
}
}
}
上述请求可以查找出包含近似applx单词的文档,例如包含apple、apply的文档等。
fuzzy
查询效率不高,需要消耗的资源比较大。
3 复合查询
复合查询就是将一些简单的查询组合在一起作为查询条件进行文档检索。
3.1 constant_score
constant_score
检索可以包装一个其它类型的查询,并返回匹配过滤器中的查询条件且具备相同评分的文档。
GET /shakespeare/_search
{
"query": {
"constant_score": {
"filter": {
"term": {
"text_entry": "apple"
}
},
"boost": 1.2
}
}
}
上述查询条件会返回包含apple单词的文档,并且评分都是1.2
3.2 bool
bool
查询可以将任意多个简单查询组合在一起,使用must
、should
、must_not
、filter
选项来表示简单查询之间的逻辑:
must
:文档必须要匹配must
下的查询条件should
:文档可以匹配也可以不匹配should
下的查询条件,匹配的文档评分会更高must_not
:匹配该选项下的查询条件的文档会被过滤,不会返回filter
:和must
类似,不同的是filter
中的条件不会参与评分。
例如:
GET /shakespeare/_search
{
"query": {
"bool": {
"must": [{
"term": {
"text_entry": {
"value": "must"
}
}}
],
"should": [{
"term": {
"text_entry": {
"value": "have"
}
}}
]
}
}
}
注意must
、should
、must_not
、filter
的值都是JSON数组,可以添加多个查询条件,包括词项搜索和全文搜索。
3.3 function_score
function_score
可以修改查询的文档的得分,用户需要定义一个查询和一到多个评分函数,评分函数会对查询到的每个文档分别计算其得分。
例如:
GET /shakespeare/_search
{
"query": {
"function_score": {
"query": {
"match": {
"text_entry": "apple"
}
},
"script_score": {
"script": {
"inline": "Math.sqrt(doc['line_id'].value)"
}
}
}
}
}
上述请求可以查找出text_entry
包含apple的文档,并且评分按照line_id
的开方计算。
function_score
查询方式内嵌了多种函数和查询方法,可以参照官方文档了解更多。
3.4 dis_max
dis_max
检索(Disjucation Max Query)和bool
检索有联系也有区别,dis_max
支持多并发查询,可以返回与任意查询条件子句匹配的任何文档类型。和bool
检索不同的是,dis_max
查询只使用最佳匹配查询条件的分数:
GET /shakespeare/_search
{
"query": {
"dis_max": {
"tie_breaker": 0.7,
"boost": 1.2,
"queries": [
{ "term": { "text_entry": "apple" } },
{ "term": { "text_entry": "watch" } }
]
}
}
}
3.5 boosting
boosting查询适用于需要对评分进行调整的场景,它会把两个查询封装在一起并降低其中一个查询条件的评分,例如:
GET /shakespeare/_search
{
"query": {
"boosting": {
"positive": {
"match": {
"text_entry": "apple"
}
},
"negative": {
"range": {
"line_id": {
"gte": 0,
"lte": 10000
}
}
},
"negative_boost": 0.2
}
}
}
上述查询条件中会降低line_id
在0到10000之间的文档的评分,会降低到原先的0.2倍。