我们在使用搜索引擎时,在输入框输入字符时,索引引擎往往会在下拉框给出推荐和提示。在ES中,该功能是通过“suggest”功能来提供的。通过将输入字符串拆分成词组项表,然后在ES的词典中进行搜索。
从总体来看,推荐可分为两大类四小类,即
Suggest:term suggest & phrase suggest
Completion:Completion suggest & Contexts suggest
推荐
推荐分为两种,即term suggest和pharse suggest。
Term Suggest
term suggest使用类似下面的模板。
GET xxx_index/_search
{
"query": { *query block*},
"suggester": {
"suggest_name1": { // suggest的名称
"text": "query_msg", // 查询字符串
"term": {
"size": 10, // 最大返回的suggest数目
"field": "xxxx", // 要推荐的字段名称
"suggester_mode": "missing|popular|always" // 3种类型的suggester mode
}
},
"suggest_name2": {
"text": "nucene",
"term": {
"sort": "score",
"field": "body",
"string_distance": "levenshtein",
"max_edits": 2,
"prefix_length": 0,
"suggest_mode": "missing"
}
}
}
}
term suggest可以使用三种suggester mode
"missing",当搜索结果中已经包含要搜索的内容,则不进行推荐。
"popular",推荐全部文档中出现频率最高的内容。
"always",无论是否有结果,都进行推荐。
推荐的内容是通过计算编辑距离来进行的,在配置参数时,可以设置:
- string_distance,编辑距离的计算方法。
- sort,选择推荐结果的排序方法,可选的方式有两种,score和frequercy。
- max_edits,最大的编辑距离,只能设置1或者2,默认为2
- prefix_length,前缀匹配长度,默认为1,即推荐时至少第一个字符时匹配的,比如,要搜索lucene,如果我输入nucene,则不会有任何推荐结果返回。如果将prefix_length设成0,则能够正常推荐lucene。
Term Suggest的其他一些使用参考此处不做赘述,可参考:
https://www.elastic.co/guide/en/elasticsearch/reference/7.2/search-suggesters-term.html
Phrase Suggest
Phrase Suggest与Term Suggest的区别在于,term suggest会将输入拆成一个个词项分别进行搜索推荐,而phrase Suggest会将其作为一个整体进行。此处还有很多细节,官方文档中,使用了将一个字段加入了多个字段使用不同的处理方式进行解析的方式作为例子,有兴趣可以参考:
https://www.elastic.co/guide/en/elasticsearch/reference/7.2/search-suggesters-phrase.html
Term Suggest
GET articles/_search
{
"suggest": {
"YOUR_SUGGESTION": {
"text": "elasticsearch is",
"term": {
"field": "body"
}
}
}
}
"suggest" : {
"YOUR_SUGGESTION" : [
{
"text" : "elasticsearch",
"offset" : 0,
"length" : 13,
"options" : [ ]
},
{
"text" : "is",
"offset" : 14,
"length" : 2,
"options" : [ ]
}
]
}
Phrase Suggest
GET articles/_search
{
"suggest": {
"YOUR_SUGGESTION": {
"text": "elasticsearch is",
"phrase": {
"field": "body"
}
}
}
}
...
"suggest" : {
"YOUR_SUGGESTION" : [
{
"text" : "elasticsearch is",
"offset" : 0,
"length" : 16,
"options" : [ ]
}
]
}
几个常用参数:
"max_errors",表示输入中最多有几个拼写错误,一般推荐设置一个较低的值,如1,2
"confidence",置信度,设为1时,只有分数超过输入词组的项才会返回,当设为0时,top N结果都会返回。
补全
Completion Suggest
补全需要在做mapping时为相关的字段设置completion类型。
PUT articles
{
"mappings": {
"properties": {
"title": {
"type": "completion"
}
}
}
}
mapping时,可以指定该字段的analyzer和search_analyzer。以及确定是否可以忽略分隔字符(使用参数preserve_separators)
同时也可以有一些其他设置。参考文档:
https://www.elastic.co/guide/en/elasticsearch/reference/7.2/search-suggesters-completion.html
在使用时,使用”completion“类型的suggest进行。
GET articles/_search?pretty
{
"size": 20,
"suggest": {
"my_suggestion": {
"prefix": "elk",
"completion": {
"field": "title"
}
}
}
}
Context Suggest
另外,补全功能还可以根据上下文提示进行。比如,对输入“star”进行提示,如果我搜索的是“film”类型,则返回“star war”,如果是“coffee”类型,则返回“star bucks",这个功能是通过在文档写入时,增加类型标签来实现的。
PUT articles
{
"mappings": {
"properties": {
"title": {
"type": "completion",
"contexts": [{
"type": "category",
"name": "item_type"
}]
}
}
}
}
插入数据
POST articles/_doc/2
{
"title": {
"input": ["Star War", "Lord of rings"],
"contexts": {
"item_type": ["film"]
}
}
}
POST articles/_doc/1
{
"title": {
"input": ["star bulk", "costa coffee"],
"contexts": {
"item_type": ["coffee"]
}
}
}
进行基于上下文的推荐
POST articles/_search
{
"suggest": {
"YOUR_SUGGESTION": {
"prefix": "star",
"completion": {
"field": "title",
"contexts": {
"item_type": ["coffee"]
}
}
}
}
}
返回结果是:
....
"text" : "star bulk",
"_index" : "articles",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"title" : {
"input" : [
"star bulk",
"costa coffee"
],
"contexts" : {
"item_type" : [
"coffee"
]
}
}
},
"contexts" : {
"item_type" : [
"coffee"
]
}
}
基于上下文的补全推荐目前有两种类型,除了上文的category以外,还可以指定一个geo类型的context进行推荐。
高亮
高亮最简单的用法,就是在query块下面设置,需要高亮的fields,这样就会在搜索结果中将命中的部分用标签包括起来。
GET articles/_search
{
"query": {
"match": {
"body": "elastic"
}
},
"highlight": {
"fields": {"body": {}},
"pre_tags": "<aaa>",
"post_tags": "</aaa>"
}
}
高亮可以定制前缀标签和后缀标签。
另有一些更高级的应用可以参考官方文档。https://www.elastic.co/guide/en/elasticsearch/reference/7.2/search-request-highlighting.html
小结
从性能上看,由于补全功能都是基于前缀匹配提供的,而且使用了独立于倒排索引的FST数据结构,其性能最高,而Term Suggest会进行分词,因此性能不如phrase suggest,从性能上看是:
Completion > Phrase > Term
从精准度来看,
Completion > Phrase > Term
从查全角度(召回率)看,
Term > Phrase > Completion
如果想知道某次suggest的类型,可以在其search API上加入typed_keys参数
POST articles/_search?typed_keys
{
"suggest": {
"YOUR_SUGGESTION": {
"prefix": "star",
"completion": {
"field": "title",
"contexts": {
"item_type": ["coffee"]
}
}
}
}
}
返回结果中会包含suggest的类型:
"completion#YOUR_SUGGESTION" : [
{
"text" : "star",
"offset" : 0,
"length" : 4,
"options" : [
{
"text" : "star bulk",
"_index" : "articles",
今天是ES认证复习的第一轮结束,粗略的把ES的相关内容过了一遍,有很多地方都没有详细地进去看。比如本章的高亮部分,其实官方文档的内容很多,但是是否都需要细细地去学习呢?我觉得也许用处不大,没有实际的应用场景,也许我细细地看过,写了文章,又很快地忘记了。我觉得实践是非常重要的,亲自在kibana里面敲一遍,印象会比较深刻。有很多东西,文章看很多遍,不实际操作,很快就会忘记。过几天我会开始下一轮,希望今年6月之前能够拿到证。我的目标不仅仅是拿到这个证,更重要的是通过这个过程,能够掌握ES的方方面面,成为这方面的专家。