Elasticsearch 7.x 检索文档的三种方式:全文搜索、词项搜索、复合搜索
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、AND
minimum_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倍。