搜索推荐
搜索推荐
POST <index>/_search
{
"suggest": {
"" : {
"text": "" ,
"term": {
"suggest_mode": "" ,
"field": ""
}
}
}
}
用户搜索的文本
field:要从哪个字段选取推荐数据
analyzer:使用哪种分词器
size:每个建议返回的最大结果数
sort:如何按照提示词项排序,参数值只可以是以下两个枚举:
missing:默认值,仅为不在索引中的词项生成建议词
popular:仅返回与搜索词文档词频或文档词频更高的建议词
always:根据 建议文本中的词项 推荐 任何匹配的建议词
一种场景:
要搜的词: 五万的宝马; 拆解这个词一个是价格一个是品牌,然后把这两个词分别应用到价格字段和品牌字段做精准匹配
这样就避免了比如一些蹭热度的标题如:"仅五万动力超过宝马"这种,因为它实际品牌可能是宝骏,提高命中程度
其实这个意思是说,一旦我精准匹配了,还需要给你推荐似是而非的词项吗? 比如"仅五万动力超过宝马"这种命中是否还要推送给你?很明显不需要的
missing就是当精准匹配了,就不需要再推荐其他可能词项了,这就像你在京东搜索框搜索宝马
,它下边会有很多推荐项.这的精准匹配指的在索引中匹配到了.
DELETE news
POST _bulk
{ "index" : { "_index" : "news","_id":1 } }
{ "title": "baoqiang bought a new hat with the same color of this font, which is very beautiful baoqiangba baoqiangda baoqiangdada baoqian baoqia"}
{ "index" : { "_index" : "news","_id":2 } }
{ "title": "baoqiangge gave birth to two children, one is upstairs, one is downstairs baoqiangba baoqiangda baoqiangdada baoqian baoqia"}
{ "index" : { "_index" : "news","_id":3} }
{ "title": "baoqiangge 's money was rolled away baoqiangba baoqiangda baoqiangdada baoqian baoqia"}
{ "index" : { "_index" : "news","_id":4} }
{ "title": "baoqiangda baoqiangda baoqiangda baoqiangda baoqiangda baoqian baoqia"}
GET /news/_search
{
"suggest": {
"my-suggestion": {
"text": "baoqing baoqiang",
"term": {
//"suggest_mode": "missing",
//大于等于搜索词频率
"suggest_mode": "popular",
//"suggest_mode":"always",
"field": "title",
//表示词项在多少个文档中出现的次数,统计文档的个数,一个文档出现多次不计算
"min_doc_freq": 3
}
}
}
}
有什么特性和区别?
phrase suggester和term suggester相比,
对建议的文本会参考上下文即其他token
同时也会基于token距离匹配
它可以基于共生和频率选出更好的建议。
为什么必须有一个mapping?
https://www.elastic.co/guide/en/elasticsearch/reference/7.17/analysis-shingle-tokenfilter.html
shingle是什么?
前面我们讲过基于字符的ngram切词组合,shingle是基于词项的;
concatenating adjacent tokens. 连接相邻词项
Shingles are often used to help speed up phrase queries, such as
match_phrase
. Rather than creating shingles using theshingles
filter, we recommend you use theindex-phrases
mapping parameter on the appropriate text field instead.提高短语查询速度,如match_phase类型的查询
不建议把shingle用于shingle过滤器,建议在text字段用于应设参数
index-phrases
例子:[ the, lazy, dog ]
= > [ the, the lazy, lazy, lazy dog, dog ]
比如最大切词是2, 它会切1个的,然后切2个,包含空格
有什么特点? 需要配置什么参数?参数分别什么作用?
shingle用在哪里?哪些场景使用?
它会给你推荐一些短语,这些短语不一定是在文档中存在的, 它是根据你的搜索词和文档内容,自动生成的一些短语, 它认为你可能想搜索的
这里的短语指的搜索结果中的:
"suggest" : {
"simple_phrase" : [
{
"text" : "Luceen and elasticsearhc",
"offset" : 0,
"length" : 24,
"options" : [
{
//这个就是推荐短语,这个不一定是文档内容,可能是基于搜索词和文档内容自动生成的
"text" : "lucene and elasticsearhc",
"highlighted" : "lucene and elasticsearhc",
"score" : 0.06261247
},
{
"text" : "lucene and elasticsearch",
"highlighted" : "lucene and elasticsearch",
"score" : 0.06183557
},
{
"text" : "luceen and elasticsearhc",
"highlighted" : "luceen and elasticsearhc",
"score" : 0.036299694
},
{
"text" : "luceen and elasticsearch",
"highlighted" : "luceen and elasticsearch",
"score" : 0.035849284
}
]
}
]
}
DELETE test_shingle
PUT test_shingle
{
"settings": {
//这个"index"名称不是可以自定义的
"index":{
//这个索引的存储属性
"number_of_shards": 1,
"number_of_replicas": 0,
"analysis":{
"analyzer": {
"mytrigram":{
"type": "custom",
"tokenizer":"standard",
"filter":["lowercase", "myfilter_shingle"]
}
},
"filter": {
"myfilter_shingle":{
"type": "shingle",
//这里虽然设置了2,3,但是一个单词还是存在的因为默认是保留一元组
"min_shingle_size": 2,
//注意key不要空格,禁用一元组
//如果设置为false,可能会报错 "At least one unigram is required but all tokens were ngrams"
//"output_unigrams": false,
"max_shingle_size": 3
}
}
}
}
},
"mappings": {
"properties": {
"title": {
"type": "text",
"fields": {
//这个是子字段,子字段是什么意思?好像就是自定义的analyzer的名字
"myfield": {
"type": "text",
"analyzer": "mytrigram"
}
}
}
}
}
}
###测试数据
POST test_shingle/_bulk
{ "index" : { "_id":1} }
{"title": "lucene and elasticsearch"}
{ "index" : {"_id":2} }
{"title": "lucene and elasticsearhc"}
{ "index" : { "_id":3} }
{"title": "lucene"}
##测试分词器
POST test_shingle/_analyze
{
"analyzer": "mytrigram",
//注意这里的组合在源数据是不一样的 前后都故意写错了
"text": ["luceen and elasticsearhc"]
}
##注意这里是POST
POST test_shingle/_search
{
"suggest": {
"text": "Luceen and elasticsearhc",
//这是类型还是自定义名称?
"myphrase": {
"phrase": {
"field": "title.myfield",
"max_errors": 2,
//候选词生成器
"direct_generator":[
{
"field":"title.myfield",
"suggest_mode":"always"
}
]
}
}
}
}
POST test_shingle/_search
{
"suggest": {
"text": "Luceen and elasticsearhc",
"simple_phrase": {
"phrase": {
"field": "title.myfield",
//最大纠正几个单词个数;即你输入的关键字错误需要给你自动纠正
"max_errors": 2,
"gram_size": 1,
"confidence": 0,
"direct_generator": [
{
"field": "title.myfield",
"suggest_mode": "always"
}
],
//高亮标签就是命中的此项高亮显示
"highlight": {
"pre_tag": "",
"post_tag": ""
}
}
}
}
}
文档: https://www.elastic.co/guide/en/elasticsearch/reference/7.17/search-suggesters.html
The likelihood of a term being misspelled even if the term exists in the dictionary. The default is 0.95, meaning 5% of the real words are misspelled.
即使单词在字典中存在,也有可能拼写错误的概率。默认值为0.95,表示有5%的真实单词是拼写错误的
- “likelihood of” 表示某个事件或情况发生的可能性。
- “being misspelled” 是一个短语,表示某个单词被拼写错误。
- “even if” 是一个连词,表示即使某个条件成立或某个情况存在。
- “the term exists in the dictionary” 表示某个单词在字典中存在。
整个句子的意思是,即使某个单词在字典中存在,仍然有可能被拼写错误。默认情况下,这个概率是0.95,也就是说有5%的真实单词会被拼写错误。
The maximum percentage of the terms considered to be misspellings in order to form a correction. This method accepts a float value in the range [0..1) as a fraction of the actual query terms or a number >=1 as an absolute number of query terms. The default is set to 1.0, meaning only corrections with at most one misspelled term are returned. Note that setting this too high can negatively impact performance. Low values like 1 or 2 are recommended; otherwise the time spend in suggest calls might exceed the time spend in query execution.
给定词项中最大纠正数量或者百分比数量,比如1就表示最大纠正一个错误词项。该方法接受一个浮点值,在范围[0…1)内作为实际查询术语的比例,或者一个大于等于1的数作为查询术语的绝对数量。默认设置为1.0,意味着只返回最多一个拼写错误术语的纠正。请注意,将此值设置得过高可能会对性能产生负面影响。建议使用较低的值,例如1或2;否则,在建议调用中花费的时间可能超过查询执行的时间。
The confidence level defines a factor applied to the input phrases score which is used as a threshold for other suggest candidates. Only candidates that score higher than the threshold will be included in the result. For instance a confidence level of 1.0 will only return suggestions that score higher than the input phrase. If set to 0.0 the top N candidates are returned. The default is 1.0.
置信度定义了一个应用于输入短语得分的因子,该得分用作其他建议候选项的阈值。只有得分高于阈值的候选项才会包含在结果中。例如,置信度为1.0将仅返回得分高于输入短语的建议。如果设置为0.0,则返回排名前N的候选项。默认值为1.0。
"confidence level" 表示置信度水平,即确定阈值的因子。 "factor applied to" 表示应用于某个因子的因子。 "input phrases score" 表示输入短语的得分。 "threshold for" 表示阈值,即一个标准或界限。 "suggest candidates" 表示建议的候选项。 "score higher than" 表示得分高于某个值。 "included in the result" 表示包含在结果中。 "confidence level of 1.0" 表示置信度水平为1.0。 "top N candidates" 表示排名前N的候选项。 "the default is 1.0" 表示默认值为1.0。 整个句子的意思是,置信度水平定义了一个应用于输入短语得分的因子,该得分用作其他建议候选项的阈值。只有得分高于阈值的候选项才会包含在结果中。例如,置信度为1.0将仅返回得分高于输入短语的建议。如果置信度设置为0.0,则返回排名前N的候选项。默认情况下,置信度为1.0。
phrase suggester使用候选生成器生成给定文本中每个项可能的项的列表。单个候选生成器类似于为文本中的每个单独的调用term suggester。生成器的输出随后与建议候选项中的候选项结合打分。目前只支持一种候选生成器,即direct_generator。建议API接受密钥直接生成器下的生成器列表;列表中的每个生成器都按原始文本中的每个项调用。
Checks each suggestion against the specified query to prune suggestions for which no matching docs exist in the index. The collate query for a suggestion is run only on the local shard from which the suggestion has been generated from. The query must be specified and it can be templated. See Search templates. The current suggestion is automatically made available as the {{suggestion}} variable, which should be used in your query. You can still specify your own template params — the suggestion value will be added to the variables you specify. Additionally, you can specify a prune to control if all phrase suggestions will be returned; when set to true the suggestions will have an additional option collate_match, which will be true if matching documents for the phrase was found, false otherwise. The default value for prune is false.
参数 collate
是用于控制是否返回所有短语建议的选项。
当 collate
参数设置为 true
时,短语建议结果将包含一个额外的选项 collate_match
,用于指示与短语匹配的文档是否存在。如果 collate_match
为 true
,则表示存在匹配的文档;如果 collate_match
为 false
,则表示没有匹配的文档。
这个参数的目的是对短语建议结果进行过滤,仅返回那些在索引中具有匹配文档的短语。通过设置 collate
参数为 true
,您可以获取到更精确的建议结果,只包含在实际数据中有匹配的短语。
需要注意的是,默认情况下 collate
参数的值为 false
,即不进行过滤,返回所有短语建议。根据您的具体需求,您可以根据是否需要过滤匹配文档来调整 collate
参数的值。
需要提供一个具体的查询语句作为 collate
参数的值,该查询语句可以包含特定的搜索条件、过滤条件、排序规则等。同时,您也可以在查询语句中使用模板,以便根据实际情况动态生成查询条件。
模板是一种在查询语句中使用占位符的方式,您可以在查询语句中定义占位符,然后在实际使用时将占位符替换为具体的值。这样可以使查询语句更加灵活和可复用。
使用模板的好处是可以根据不同的场景和需求生成不同的查询语句,而不需要每次都手动编写和修改查询语句。这样可以提高代码的可维护性和灵活性。
在使用 collate
参数时,您可以根据需要编写具体的查询语句,并在其中使用模板来灵活地生成查询条件,以便满足您的需求。
自动补全,自动完成,支持三种查询【前缀查询(prefix)模糊查询(fuzzy)正则表达式查询(regex)】 ,主要针对的应用场景就是"Auto Completion"。 此场景下用户每输入一个字符的时候,就需要即时发送一次查询请求到后端查找匹配项,在用户输入速度较高的情况下对后端响应速度要求比较苛刻。因此实现上它和前面两个Suggester采用了不同的数据结构,索引并非通过倒排来完成,而是将analyze过的数据编码成FST和索引一起存放。对于一个open状态的索引,FST会被ES整个装载到内存里的,进行前缀查找速度极快。但是FST只能用于前缀查找,这也是Completion Suggester的局限所在。
search_as_you_type类型构建FST存到内存中,支撑complete的高性能推荐
FST压缩比例的特别高,一个类似字母树的结构
它的高性能基于FST的压缩和内存
内存代价太大 性能高是通过大量的内存换来的
只能前缀搜索,假如用户输入的不是前缀 召回率可能很低
只适合前缀推荐
需要结合特定的complete类型
DELETE test_idx_compolte_suggest
//POST 可以用来执行数据相关的查询插入操作
//PUT可以用来进行元数据相关的操作,比如插入索引
PUT test_idx_compolte_suggest
{
"mappings": {
"properties": {
//字段名
"title": {
"type": "text",
"analyzer": "ik_max_word",
"fields": {
"suggest_for_title": {
"type": "completion",
"analyzer": "ik_max_word"
}
}
},
//another column name
"content": {
"type":"text",
"analyzer":"ik_max_word"
}
}
}
}
##插入数据
POST _bulk
{"index":{"_index":"test_idx_compolte_suggest","_id":1}}
{"title":"宝马X5 两万公里准新车","content":"这里是宝马X5图文描述"}
{"index":{"_index":"test_idx_compolte_suggest","_id":2}}
{"title":"宝马5系","content":"这里是奥迪A6图文描述"}
{"index":{"_index":"test_idx_compolte_suggest","_id":3}}
{"title":"宝马3系","content":"这里是奔驰图文描述"}
{"index":{"_index":"test_idx_compolte_suggest","_id":4}}
{"title":"奥迪Q5 两万公里准新车","content":"这里是宝马X5图文描述"}
{"index":{"_index":"test_idx_compolte_suggest","_id":5}}
{"title":"奥迪A6 无敌车况","content":"这里是奥迪A6图文描述"}
{"index":{"_index":"test_idx_compolte_suggest","_id":6}}
{"title":"奥迪双钻","content":"这里是奔驰图文描述"}
{"index":{"_index":"test_idx_compolte_suggest","_id":7}}
{"title":"奔驰AMG 两万公里准新车","content":"这里是宝马X5图文描述"}
{"index":{"_index":"test_idx_compolte_suggest","_id":8}}
{"title":"奔驰大G 无敌车况","content":"这里是奥迪A6图文描述"}
{"index":{"_index":"test_idx_compolte_suggest","_id":9}}
{"title":"奔驰C260","content":"这里是奔驰图文描述"}
{"index":{"_index":"test_idx_compolte_suggest","_id":10}}
{"title":"nir奔驰C260","content":"这里是奔驰图文描述"}
##前缀匹配
GET test_idx_compolte_suggest/_search
{
"suggest": {
//定义suggest内容
"my_suggest_for_car": {
//suggest定义前缀
"prefix":"奔马",
//如果使用正则就定义regex,正则性能很差不建议
//"regex":"baoma",
// suggest定义field及completion信息
"completion":{
"field":"title.suggest_for_title",
//正则不可以使用fuzzy
"fuzzy":{
//可以看设置为0,1,2的区别
//这个参数主要是为了对你的搜索词进行纠错
"fuzziness":2
},
//是否去重
"skip_duplicates":true
}
}
}
}
##正则匹配
##正则性能很差不建议
##这里的正则也是匹配前缀
GET test_idx_compolte_suggest/_search
{
"suggest": {
"my_suggest_for_car": {
"regex":".*",
"completion":{
"field":"title.suggest_for_title",
"skip_duplicates":true
}
}
}
}
它的设计目的主要是针对completion Suggester的一些缺点进行改进,比如当数据量达到一定阈值的时候性能下降(比如内存不够进行磁盘置换),context希望通过数据过滤来达到降低数量提高性能的目的.
它是建立在completion基础上增加了过滤功能.
完成建议者会考虑索引中的所有文档,但是通常来说,我们在进行智能推荐的时候最好通过某些条件过滤,并且有可能会针对某些特性提升权重。
context
的名字,用于区分同一个索引中不同的 context
对象。需要在查询的时候指定当前namecontext
对象的类型,目前支持两种:category和geo,分别用于对suggest item分类和指定地理位置。# 地理位置筛选器
PUT place/_doc/3
{
"suggest": {
"input": "timmy's",
"contexts": {
"location": [
{
"lat": 43.6624803,
"lon": -79.3863353
},
{
"lat": 43.6624718,
"lon": -79.3873227
}
]
}
}
}
POST place/_search
{
"suggest": {
"place_suggestion": {
"prefix": "tim",
"completion": {
"field": "suggest",
"contexts": {
"location": {
"lat": 43.662,
"lon": -79.380
}
}
}
}
}
}
DELETE test_idx_context_suggest
##定义索引
PUT test_idx_context_suggest
{
"mappings": {
"properties": {
//定义索引的suggest属性;这个是关键字
"suggest":{
//它的type仍然是completion
"type":"completion",
//可以定义多个
//这个是为了过滤用?TODO
"contexts":[
//每个映射包含name和type基本属性
{
//定义了这个名字如何使用呢? 这个相当于一个元字段
//插入数据时指定"my_context_name_category":["food","drink"],就相当于
//给这条数据指定了分类,在智能推荐时就可以只从这些分类或者类型的数据中进行筛选推荐
"name": "my_context_name_category",
//定义这个suggest支持的数据类型,数据类型是field type
"type": "category"
},
{
"name": "my_context_name_localtion",
"type": "geo",
//地理精度1-12,分别代表单位厘米,分米..
"precision": 4
}
]
}
}
}
}
##插入数据
POST test_idx_context_suggest/_doc/1
{
"suggest":{
//这个表示可能的智能推荐的词
"input": [ "timmy's", "starbucks", "dunkin donuts" ],
//这个就是上面说明的一个用户,给这个数据定义好分类
//,在推荐的时候只要满足这个分类才会被用作智能推荐
"contexts": {
//这个分类的值是你自定义的
"my_context_name_category": [ "cafe", "food" ]
}
}
}
##插入2
PUT test_idx_context_suggest/_doc/2
{
"suggest": {
//注意这条数据和上面有个重复的重复的数据,但是类型不一致
"input": [ "monkey", "timmy's", "Lamborghini" ],
"contexts": {
"my_context_name_category": [ "money"]
}
}
}
##智能建议测试
GET test_idx_context_suggest/_search
POST test_idx_context_suggest/_search?pretty
{
"suggest": {
//你的suggest自定义名称
"my_suggestion_name002": {
//索引中匹配以sta前缀的词
"prefix": "sta",
"completion": {
"field": "suggest",
"size": 10,
//如果不适用context就是对所有数据进行智能推荐
"contexts": {
"my_context_name_category": [ "cafe", "restaurants" ]
}
}
}
}
}
##限制分类,测试否还能被匹配
POST test_idx_context_suggest/_search?pretty
{
"suggest": {
//你的suggest自定义名称
"my_suggestion_name002": {
//tim开头的在两个分类中都有,这里限制cafe分类,查看是否money分类的数据是否被匹配
"prefix": "tim",
"completion": {
"field": "suggest",
"size": 10,
//如果不适用context就是对所有数据进行智能推荐
"contexts": {
"my_context_name_category": [ "cafe", "restaurants" ]
}
}
}
}
}
##增加money分类查看结果
POST test_idx_context_suggest/_search?pretty
{
"suggest": {
//你的suggest自定义名称
"my_suggestion_name002": {
//tim开头的在两个分类中都有,这里限制cafe分类,查看是否money分类的数据是否被匹配
"prefix": "tim",
"completion": {
"field": "suggest",
"size": 10,
//如果不适用context就是对所有数据进行智能推荐
"contexts": {
"my_context_name_category": [
//增加分类后两个tim开头的都查出来了
{"context":"cafe"},
{"context":"money"}
]
}
}
}
}
}
##context增加排序权重
POST test_idx_context_suggest/_search?pretty
{
"suggest": {
//你的suggest自定义名称
"my_suggestion_name002": {
//tim开头的在两个分类中都有,这里限制cafe分类,查看是否money分类的数据是否被匹配
"prefix": "tim",
"completion": {
"field": "suggest",
"size": 10,
//如果不适用context就是对所有数据进行智能推荐
"contexts": {
"my_context_name_category": [
//增加分类后两个tim开头的都查出来了
{"context":"cafe"},
{"context":"money", "boost":2}
]
}
}
}
}
}
# 定义一个名为 my_context_name_category 的类别 Context,其中类别是从 my_category 字段中读取的。
# 定义一个名为 my_context_name_localtion 的地理 Context,其中的类别是从 my_location 字段中读取的
DELETE test_idx_context_suggest_category_column
PUT test_idx_context_suggest_category_column
{
"mappings": {
"properties": {
"suggest": {
"type": "completion",
"contexts": [
{
"name": "my_context_name_category",
"type": "category",
//path就是定义分类的字段,主要目的就是减少插入数据的语法简化
//可以对比插入数据的区别进行对比
"path": "my_category"
},
{
"name": "my_context_name_localtion",
"type": "geo",
"precision": 4,
"path": "my_location"
}
]
},
"my_location": {
"type": "geo_point"
}
}
}
}
# 如果映射有路径,那么以下索引请求就足以添加类别
# 这些建议将与咖啡馆和食品类别相关联
# 如果上下文映射引用另一个字段并且类别被明确索引,则建议将使用两组类别进行索引
PUT test_idx_context_suggest_category_column/_doc/1
{
"suggest": ["timmy's", "starbucks", "dunkin donuts"],
"my_category": ["cafe", "food"]
}
POST test_idx_context_suggest_category_column/_search?pretty
{
"suggest": {
"place_suggestion": {
"prefix": "tim",
"completion": {
"field": "suggest",
"contexts": {
"my_context_name_category": [
{ "context": "cafe" }
]
}
}
}
}
}
文档:
https://www.elastic.co/guide/en/elasticsearch/reference/7.17/mapping-types.html