【Elasticsearch】Elasticsearch中 使用Suggesters 推荐推荐查询
文章目录
Suggesters
Suggests similar looking terms based on a provided text by using a suggester.
顾名思义,就是推荐查询你,在你输一些关键词的时候对这些词语一个建议。(百度搜索框中你每次输入的值都会帮你纠错,或者进行一个搜索推荐就是这种方式实现)
Suggesters
在有4种不同的类型:
在官方文档中也是给出了详细的解释
- Term suggester
- Phrase Suggester
- Completion Suggester
- Context Suggester
Term suggester
- 国际惯例,先准备基础数据
POST product_en/_bulk
{"index":{"_id":"1"}}
{"title":"my english book","desc":"this is noob english dictionary","price":13.90,"tag":["dictionary","english","noob"]}
{"index":{"_id":"2"}}
{"title":"my chinese book","desc":"this is noob chinese dictionary","price":15.90,"tag":["dictionary","chinese","noob"]}
{"index":{"_id":"3"}}
{"title":"switch oled","desc":"Nintendo Switch","price":2499,"tag":["game","switch","video game","Handheld game console"]}
{"index":{"_id":"4"}}
{"title":"iPhone 14","desc":"smart mobile phone","price":8999,"tag":["Apple","mobile phone","IOS"]}
{"index":{"_id":"5"}}
{"title":"IPad","desc":"smart tablet","price":12990,"tag":["tablet","Apple","IOS"]}
{"index":{"_id":"6"}}
{"title":"Dove Chocolate","desc":"Dove, enjoy the silky","price":8.00,"tag":["chocolate","Dove","silky"]}
- 推荐查询[term suggest]单个短语进行推荐
GET product_en/_search
{
"suggest":{
"my_suggestions":{
"text": "englis",
"term":{
"suggest_mode":"always",
"field":"title"
}
}
}
}
- 结果
可以看出虽然在查询的时候,故意写错了”englis“ 这个单词,elastic还是根据term suggest 推荐返回了一个推荐的值。(还有一定的纠错功能)【在options 这个对象中】
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 0,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"suggest": {
"my_suggestions": [
{
"text": "englis",
"offset": 0,
"length": 6,
"options": [
{
"text": "english",
"score": 0.8333333,
"freq": 1
}
]
}
]
}
}
- 同样也可以响官方文档给出的示例一样,可以多指定机构几个”suggestion“
Several suggestions can be specified per request.(可以为每个请求指定几个建议。)
GET product_en/_search
{
"suggest":{
"my_suggestions_1":{
"text": "phone",
"term":{
"suggest_mode":"popular",
"field":"title"
}
},
"my_suggestions_2":{
"text": "englis",
"term":{
"suggest_mode":"always",
"field":"title"
}
}
}
}
- 结果:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 0,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"suggest": {
"my_suggestions_1": [
{
"text": "phone",
"offset": 0,
"length": 5,
"options": []
}
],
"my_suggestions_2": [
{
"text": "englis",
"offset": 0,
"length": 6,
"options": [
{
"text": "english",
"score": 0.8333333,
"freq": 1
}
]
}
]
}
}
细心的同学可能发现上面的一个字段叫:suggest_mode
看了下官方文档一脸懵。
The suggest mode controls what suggestions are included or controls for what suggest text terms, suggestions should be suggested. Three possible values can be specified:
missing: Only provide suggestions for suggest text terms that are not in the index. This is the default.
popular: Only suggest suggestions that occur in more docs than the original suggest text term.
always: Suggest any matching suggestions based on terms in the suggest text.
其实大致意思如下,(可以按照对应的值传入后体验下):
- suggest_mode:搜索推荐的推荐模式,参数值亦是枚举:
- missing:默认值,仅为不在索引中的词项生成建议词:仅仅返回可推荐的词语,如果已经精确匹配到了一个文档中的内容,就不会再进行“纠错”或者“推荐”
- popular:仅返回与搜索词文档词频或文档词频更高的建议词:意思值返回返回文档词频更高的词语。比如:文档内容中同时出现了"book"和“books” 但是“books”这个单词在整合文档中出现的次数比"book"出现的次数多,那么elastic就回去推荐“books”这个词,但是输入的此项并不推荐。
- always:根据 建议文本中的词项 推荐 任何匹配的建议词,推荐所有建议,并不做限制。
Phrase Suggester
这个名字的意思就是,短语建议。
官方文档这样写道:
The term suggester provides a very convenient API to access word alternatives on a per token basis within a certain string distance. The API allows accessing each token in the stream individually while suggest-selection is left to the API consumer. Yet, often pre-selected suggestions are required in order to present to the end-user. The phrase suggester adds additional logic on top of the term suggester to select entire corrected phrases instead of individual tokens weighted based on ngram-language models. In practice this suggester will be able to make better decisions about which tokens to pick based on co-occurrence and frequencies.
In general the phrase suggester requires special mapping up front to work. The phrase suggester examples on this page need the following mapping to work. The reverse analyzer is used only in the last example.(这段话的大致意思就是如果我们要去使用Phrase Suggester 的话,我们应该按照下面这个例子创建一个特殊的索引文档来使用)。接下来我们看以下这个特殊的mapping:
PUT test
{
"settings": {
"index": {
"number_of_shards": 1,
"analysis": {
"analyzer": {
"trigram": {
"type": "custom",
"tokenizer": "standard",
"filter": ["lowercase","shingle"]
},
"reverse": {
"type": "custom",
"tokenizer": "standard",
"filter": ["lowercase","reverse"]
}
},
"filter": {
"shingle": {
"type": "shingle",
"min_shingle_size": 2,
"max_shingle_size": 3
}
}
}
}
},
"mappings": {
"properties": {
"title": {
"type": "text",
"fields": {
"trigram": {
"type": "text",
"analyzer": "trigram"
},
"reverse": {
"type": "text",
"analyzer": "reverse"
}
}
}
}
}
}
细心的人应该发现了这个mapping使用了分片。而且创建了一个自定义分词器,其中切词器tokenizer
官方使用了默认的standard。和自定义的shingle
令牌过滤器。这里可能需要引入一个新的令牌过滤器。这个令牌过滤器叫shingle
。shingle 官方文档 这样解释道:
1、Add shingles, or word n-grams, to a token stream by concatenating adjacent tokens. By default, the shingle token filter outputs two-word shingles and unigrams.
2、For example, many tokenizers convert the lazy dog to [ the, lazy, dog ]. You can use the shingle filter to add two-word shingles to this stream: [ the, the lazy, lazy, lazy dog, dog ].
上面表示,你可以使用shingle
把 [ the, lazy, dog ]
通过不同力度切分为多种不同的短语组合,因为种的例子是切分后的结果。(各位老板感觉是不是很像trigram
)
感兴趣的老铁可以感受一下,我给各位准备好了示例。
# 使用 trigram 进行分词
GET test/_analyze
{
"analyzer": "trigram",
"text":"lucene and elasticsearch"
}
# 使用 shingle
GET test/_analyze
{
"tokenizer": "whitespace",
"filter": [ "shingle" ],
"text": "lucene and elasticsearch"
}
还有就是
min_shingle_size
、max_shingle_size:
这两参数:是可以设置你的短语分词力度。这里最小设置了2,在这样的设置下结果展示如下:(感兴趣的小伙伴可以去调试以下别的参数)
{
"tokens": [
{
"token": "lucene",
"start_offset": 0,
"end_offset": 6,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "lucene and",
"start_offset": 0,
"end_offset": 10,
"type": "shingle",
"position": 0,
"positionLength": 2
},
{
"token": "lucene and elasticsearch",
"start_offset": 0,
"end_offset": 24,
"type": "shingle",
"position": 0,
"positionLength": 3
},
{
"token": "and",
"start_offset": 7,
"end_offset": 10,
"type": "<ALPHANUM>",
"position": 1
},
{
"token": "and elasticsearch",
"start_offset": 7,
"end_offset": 24,
"type": "shingle",
"position": 1,
"positionLength": 2
},
{
"token": "elasticsearch",
"start_offset": 11,
"end_offset": 24,
"type": "<ALPHANUM>",
"position": 2
}
]
}
这里再拓展一个参数,加到 shingle
里面
"shingle": {
"type": "shingle",
"min_shingle_size": 2,
"max_shingle_size": 3,
## 下面这个(output_unigrams)是关闭原始词项的开关(默认打开 true),
## 执行后不会出现单个此项的结果,执行时删除此2行
"output_unigrams": false
}
官方文档的意思是:
output_unigrams
:(Optional, Boolean) If true, the output includes the original input tokens. If false, the output only includes shingles; the original input tokens are removed. Defaults to true.
大致意思就是,结果中是否需要出现原词项(不明白?接着往下看,我会以一个例子的形式为你解释什么叫output_unigrams
)
这时候通过分词器进行分词时候就没有单个单词的option了(一般实际使用时候去操作合这个开关)。这里买下一个伏笔,这个开关会影响到 Phrase Suggester 的使用。想了解可以继续往下看。
- 学习了和创建好上面的mapping后,接下来执行测试数据
下面这段是数据有些单词让我进行了一些特殊的处理。把单词字母调换来验证。
POST test/_bulk
{"index":{"_id":1}}
{"title":"lucene and elasticsearch"}
{"index":{"_id":2}}
{"title":"lucene and elasticsearhc"}
{"index":{"_id":3}}
{"title":"luceen and elasticsearch"}
- 进行查询,并且按照管饭示例进行结果高亮
GET test/_search
{
"suggest": {
"text": "Luceen and elasticsearhc",
"simple_phrase": {
"phrase": {
"field": "title.trigram",
"max_errors": 2,
"gram_size":1,
"confidence":1,
"direct_generator": [
{
"field": "title.trigram",
"suggest_mode": "always"
}
],
"highlight": {
"pre_tag": "<em>",
"post_tag": "</em>"
}
}
}
}
}
- 结果 发现es 把我们输入的错误单词都进行了纠错,并且按照文档中出现的此项进行了推荐(我只能说Es牛B…)
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 0,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"suggest": {
"simple_phrase": [
{
"text": "Luceen and elasticsearhc",
"offset": 0,
"length": 24,
"options": [
{
"text": "lucene and elasticsearch",
"highlighted": "<em>lucene</em> and <em>elasticsearch</em>",
"score": 0.049228575
},
{
"text": "luceen and elasticsearch",
"highlighted": "luceen and <em>elasticsearch</em>",
"score": 0.04369737
},
{
"text": "lucene and elasticsearhc",
"highlighted": "<em>lucene</em> and elasticsearhc",
"score": 0.041798845
}
]
}
]
}
}
这里为小伙伴解释一下上面关于output_unigrams
这个参数的使用小问题:
使用以下语句删 test 这个mapping 然后重新创建这个mapping,并且把output_unigrams
这个开管打开。然后再次填入相同的数据,使用上面的查询语句进行查询的时候,我么会发现。es报错了?
DELETE test
- 报错信息如下:
At least one unigram is required but all tokens were ngrams
{
"error": {
"root_cause": [
{
"type": "illegal_state_exception",
"reason": "At least one unigram is required but all tokens were ngrams"
}
],
"type": "search_phase_execution_exception",
"reason": "all shards failed",
"phase": "query",
"grouped": true,
"failed_shards": [
{
"shard": 0,
"index": "test",
"node": "xLs8XZPuTlGCU3Ac9hak1g",
"reason": {
"type": "illegal_state_exception",
"reason": "At least one unigram is required but all tokens were ngrams"
}
}
],
"caused_by": {
"type": "illegal_state_exception",
"reason": "At least one unigram is required but all tokens were ngrams",
"caused_by": {
"type": "illegal_state_exception",
"reason": "At least one unigram is required but all tokens were ngrams"
}
}
},
"status": 500
}
这是为什么呢?
查阅官方文档得知,这里可以去官方文档去查看就在Phrase Suggester 这一栏可以找到。在使用 Phrase Suggester 的时候,我么需要指定Candidate Generators
候选者生成器,这也是我们Query DSL 语句中,需要指定的一个字段direct_generator
。官方也给出解释了其含义。
Candidate Generators:
The phrase suggester uses candidate generators to produce a list of possible terms per term in the given text. A single candidate generator is similar to a term suggester called for each individual term in the text. The output of the generators is subsequently scored in combination with the candidates from the other terms for suggestion candidates.
Currently only one type of candidate generator is supported, the direct_generator. The Phrase suggest API accepts a list of generators under the key direct_generator; each of the generators in the list is called per term in the original text.
上文的大致意思是:
关于direct_generator:phrase suggester使用时候选定的生成器生成给定文本中每个项可能的项的列表。单个候选生成器类似于为文本中的每个单独的调用term suggester。生成器的输出随后与建议候选项中的候选项结合打分。目前只支持一种候选生成器,即direct_generator。建议API直接生成器下的生成器列表;列表中的每个生成器都按原始文本中的每个项调用。(按照这个意思来看的话,这个短语推荐看来也是通过 term suggester实现的并且有大量的内存计算)
既然都是term 实现的,那么term又是更加每个此项进行推荐,当你关闭了output_unigrams
这个参数的时候,不会有再有单个词汇推荐了,这样的话候生成器也无法正常工作了,也应对了官方文档的解释,phrase suggester是基于term suggester 和 direct_generato配合实现的。
Completion Suggester
The completion suggester provides auto-complete/search-as-you-type functionality. This is a navigational feature to guide users to relevant results as they are typing, improving search precision. It is not meant for spell correction or did-you-mean functionality like the term or phrase suggesters.
Ideally, auto-complete functionality should be as fast as a user types to provide instant feedback relevant to what a user has already typed in. Hence, completion suggester is optimized for speed. The suggester uses data structures that enable fast lookups, but are costly to build and are stored in-memory.
大致意思就是,它主要针对的应用场景就是"Auto Completion"(自动匹配),此场景下用户每输入一个字符的时候,就需要即时发送一次查询请求到后端查找匹配项,在用户输入速度较高的情况下对后端响应速度要求比较苛刻,是一种自动完全补全,而且是基于内存的FST结构,感兴趣的同学可以看一下,基于这个结构是一种压缩技术,这种技术可以把TB级别的数据压缩GB,可想而知性能有多强。 因此实现上它和前面两个Suggester采用了不同的数据结构,索引并非单单通过倒排来完成,而是将analyze过的数据编码成FST和索引一起存放。但是由于使用了FST,和类似于AC自动机的匹配技术,缺点就是只能使用前缀索引
- 话不多说上mapping
可以看出,这mapping和之前的mapping在字段定义上有了一些不同,我们需要在指定建议字段的时候专门去指定为completion
类型。
PUT suggest_iphone
{
"mappings": {
"properties": {
"title":{
"type": "text",
"analyzer": "ik_max_word",
"fields": {
"suggest":{
"type":"completion",
"analyzer":"ik_max_word"
}
}
},
"content":{
"type":"text",
"analyzer": "ik_max_word"
}
}
}
}
- 批量数据
POST _bulk
{"index":{"_index":"suggest_iphone","_id":1}}
{"title":"IPhone 14","content":"年度旗舰,超级性能"}
{"index":{"_index":"suggest_iphone","_id":2}}
{"title":"IPhone 12","content":"我是14它弟"}
{"index":{"_index":"suggest_iphone","_id":3}}
{"title":"IPhone 11","content":"我是假货"}
{"index":{"_index":"suggest_iphone","_id":4}}
{"title":"IPhone 10 ","content":"我其实叫IPhone X"}
{"index":{"_index":"suggest_iphone","_id":5}}
{"title":"IPhone 8","content":"我是里程碑的机器,我还有Home键位"}
{"index":{"_index":"suggest_iphone","_id":6}}
{"title":"IPhone 7","content":"我是IPhone7它弟"}
{"index":{"_index":"suggest_iphone","_id":7}}
{"title":"IPhone 6s","content":"我是单摄像头"}
{"index":{"_index":"suggest_iphone","_id":8}}
{"title":"IPhone 6","content":"是最没用,而且最垃圾一代"}
{"index":{"_index":"suggest_iphone","_id":9}}
{"title":"IPhone 5s","content":"我是方方正正,加长IPhone5s"}
{"index":{"_index":"suggest_iphone","_id":10}}
{"title":"IPhone 5","content":"我是方方正正,加长IPhone4"}
- 开始查询
# 这些suggest 是相互结合起来使用
# 1、completion
GET suggest_iphone/_search?pretty
{
"suggest": {
"phone_suggest": {
"text": "IPhone",
"completion": {
"field": "title.suggest"
}
}
}
}
# 2、模糊查询,都是基于 prefix 前缀查询,官方说明只支持前缀的查询。(注意这里这里的Iphone 并没有输入完全,是通过模糊查询出来的)
GET suggest_iphone/_search
{
"suggest": {
"phone_suggest": {
"text": "Iphon 6s",
"completion": {
"field": "title.suggest",
"skip_duplicates":true,
"fuzzy":{
"fuzziness":1
}
}
}
}
}
# 3、模糊查询,都是基于 prefix 前缀查询,官方说明只支持前缀的查询。(其实和第二种没什么区别 )
GET suggest_iphone/_search
{
"suggest": {
"phone_suggest": {
"prefix": "Iphon",
"completion": {
"field": "title.suggest",
"skip_duplicates":true,
"fuzzy":{
"fuzziness":1
}
}
}
}
}
- 查询结果
结果
# 1、completion 结果
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 0,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"suggest": {
"phone_suggest": [
{
"text": "IPhone",
"offset": 0,
"length": 6,
"options": [
{
"text": "IPhone 10 ",
"_index": "suggest_iphone",
"_id": "4",
"_score": 1,
"_source": {
"title": "IPhone 10 ",
"content": "我其实叫IPhone X"
}
},
{
"text": "IPhone 11",
"_index": "suggest_iphone",
"_id": "3",
"_score": 1,
"_source": {
"title": "IPhone 11",
"content": "我是假货"
}
},
{
"text": "IPhone 12",
"_index": "suggest_iphone",
"_id": "2",
"_score": 1,
"_source": {
"title": "IPhone 12",
"content": "我是14它弟"
}
},
{
"text": "IPhone 14",
"_index": "suggest_iphone",
"_id": "1",
"_score": 1,
"_source": {
"title": "IPhone 14",
"content": "年度旗舰,超级性能"
}
},
{
"text": "IPhone 5",
"_index": "suggest_iphone",
"_id": "10",
"_score": 1,
"_source": {
"title": "IPhone 5",
"content": "我是方方正正,加长IPhone4"
}
}
]
}
]
}
}
结果
# 2、模糊查询,都是基于 prefix 前缀查询,官方说明只支持前缀的查询。(模糊查询查出结果)
{
"took": 0,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 0,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"suggest": {
"phone_suggest": [
{
"text": "Iphon 6s",
"offset": 0,
"length": 8,
"options": [
{
"text": "IPhone 6s",
"_index": "suggest_iphone",
"_id": "7",
"_score": 5,
"_source": {
"title": "IPhone 6s",
"content": "我是单摄像头"
}
}
]
}
]
}
}
结果
# 3、模糊查询,都是基于 prefix 前缀查询,官方说明只支持前缀的查询。
{
"took": 0,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 0,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"suggest": {
"phone_suggest": [
{
"text": "Iphon 6s",
"offset": 0,
"length": 8,
"options": [
{
"text": "IPhone 6s",
"_index": "suggest_iphone",
"_id": "7",
"_score": 5,
"_source": {
"title": "IPhone 6s",
"content": "我是单摄像头"
}
}
]
}
]
}
}
Context Suggester
The completion suggester considers all documents in the index, but it is often desirable to serve suggestions filtered and/or boosted by some criteria. For example, you want to suggest song titles filtered by certain artists or you want to boost song titles based on their genre.
To achieve suggestion filtering and/or boosting, you can add context mappings while configuring a completion field. You can define multiple context mappings for a completion field. Every context mapping has a unique name and a type. There are two types: category and geo. Context mappings are configured under the contexts parameter in the field mapping.
大致意思就是:completion suggester会考虑索引中的所有文档,但有些情况下我们希望在复合一定的过滤条件的范围内获得suggest。
为了实现过滤或增强suggest,您可以在配置completion字段的mapping时添加上context mappings。可以为completion字段定义多个上context mappings。每个context mappings都有唯一的name和type。有两种type:category【类型】 和 geo【地理位置】。上下文映射在字段映射中的contexts参数下配置。
DELETE place
PUT place
{
"mappings": {
"properties": {
"suggest": {
"type": "completion",
"contexts": [
{
"name": "place_type",
"type": "category"
},
{
"name": "location",
"type": "geo",
"precision": 4
}
]
}
}
}
}
- 加入数据
# 添加数据并且指定对应的context数据
PUT place/_doc/1
{
"suggest": {
"input": [ "timmy's", "starbucks", "dunkin donuts" ],
"contexts": {
"place_type": [ "cafe", "food" ]
}
}
}
PUT place/_doc/2
{
"suggest": {
"input": [ "monkey", "timmy's", "Lamborghini" ],
"contexts": {
"place_type": [ "money"]
}
}
}
PUT place/_doc/3
{
"suggest": {
"input": "timmy's",
"contexts": {
"location": [
{
"lat": 43.6624803,
"lon": -79.3863353
},
{
"lat": 43.6624718,
"lon": -79.3873227
}
]
}
}
}
- 查询演示
# 1、通过近似地位坐标经纬度进行推荐查推荐
POST place/_search
{
"suggest": {
"place_suggestion": {
"prefix": "tim",
"completion": {
"field": "suggest",
"size": 10,
"contexts": {
"location": {
"lat": 43.662,
"lon": -79.380
}
}
}
}
}
}
# 2、通过 contexts 过滤掉部分不需要智能推荐的数据
GET place/_search
{
"suggest": {
"my_place_suggest": {
"text": "star",
"completion": {
"field": "suggest",
"size":10,
"contexts":{
"place_type": [ "cafe", "restaurants" ]
}
}
}
}
}
# 3、使用 上文进行查询并且指定按照指定boot指定的内容进行排序
GET place/_search
{
"suggest": {
"my_suggest": {
"text": "timmy",
"completion": {
"field": "suggest",
"size": 10,
"contexts": {
"place_type": [
{
"context": "money"
},
{
"context": "food","boost":2
}
]
}
}
}
}
}
- 查询结果
# 1、通过近似地位坐标经纬度进行推荐查推荐
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 0,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"suggest": {
"place_suggestion": [
{
"text": "tim",
"offset": 0,
"length": 3,
"options": [
{
"text": "timmy's",
"_index": "place",
"_id": "3",
"_score": 1,
"_source": {
"suggest": {
"input": "timmy's",
"contexts": {
"location": [
{
"lat": 43.6624803,
"lon": -79.3863353
},
{
"lat": 43.6624718,
"lon": -79.3873227
}
]
}
}
},
"contexts": {
"location": [
"dpz8"
]
}
}
]
}
]
}
}
# 2、通过 contexts 过滤掉部分不需要智能推荐的数据
{
"took": 0,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 0,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"suggest": {
"my_place_suggest": [
{
"text": "star",
"offset": 0,
"length": 4,
"options": [
{
"text": "starbucks",
"_index": "place",
"_id": "1",
"_score": 1,
"_source": {
"suggest": {
"input": [
"timmy's",
"starbucks",
"dunkin donuts"
],
"contexts": {
"place_type": [
"cafe",
"food"
]
}
}
},
"contexts": {
"place_type": [
"cafe"
]
}
}
]
}
]
}
}
# 3、使用 上文进行查询并且指定按照指定boot指定的内容进行排序
{
"took": 0,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 0,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"suggest": {
"my_suggest": [
{
"text": "timmy",
"offset": 0,
"length": 5,
"options": [
{
"text": "timmy's",
"_index": "place",
"_id": "1",
"_score": 2,
"_source": {
"suggest": {
"input": [
"timmy's",
"starbucks",
"dunkin donuts"
],
"contexts": {
"place_type": [
"cafe",
"food"
]
}
}
},
"contexts": {
"place_type": [
"food"
]
}
},
{
"text": "timmy's",
"_index": "place",
"_id": "2",
"_score": 1,
"_source": {
"suggest": {
"input": [
"monkey",
"timmy's",
"Lamborghini"
],
"contexts": {
"place_type": [
"money"
]
}
}
},
"contexts": {
"place_type": [
"money"
]
}
}
]
}
]
}
}
同样 Context Suggester 也可以在同一个document中设置多个context例如:
DELETE place_path_category
PUT place_path_category
{
"mappings": {
"properties": {
"suggest": {
"type": "completion",
"contexts": [
{
"name": "place_type",
"type": "category",
"path": "cat"
},
{
"name": "location",
"type": "geo",
"precision": 4,
"path": "loc"
}
]
},
"loc": {
"type": "geo_point"
}
}
}
}
- 添加数据
PUT place_path_category/_doc/1
{
"suggest": [
"timmy's",
"starbucks",
"dunkin donuts"
],
"cat": [
"cafe",
"food"
],
"loc": [
{
"lat": 43.6624803,
"lon": -79.3863353
}
]
}
PUT place_path_category/_doc/2
{
"suggest": ["linked's", "snow city", "seven eleven"],
"cat": ["fast food", "shop"],
"loc": [
{
"lat": 49.6624803,
"lon": -65.3863353
}
]
}
- 关联查询
# 通过 path 进行关联
POST place_path_category/_search?pretty
{
"suggest": {
"place_suggestion": {
"prefix": "link",
"completion": {
"field": "suggest",
"contexts": {
"place_type": [
{ "context": "fast food" }
]
}
}
}
}
- 查询结果
{
"took": 0,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 0,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"suggest": {
"place_suggestion": [
{
"text": "link",
"offset": 0,
"length": 4,
"options": [
{
"text": "linked's",
"_index": "place_path_category",
"_id": "2",
"_score": 1,
"_source": {
"suggest": [
"linked's",
"snow city",
"seven eleven"
],
"cat": [
"fast food",
"shop"
],
"loc": [
{
"lat": 49.6624803,
"lon": -65.3863353
}
]
},
"contexts": {
"place_type": [
"fast food"
]
}
}
]
}
]
}
}