ElasticSearch7.7 suggesters 教程

1. suggesters 一共有四种

类别中文描述
Term suggester术语推荐
Phrase suggester短语推荐
Completion suggester完成推荐,也被称为auto completion自动完成
Context suggester上下文推荐

这几种没有好坏之分,他们分别有自己适用的场景,下面我们来一一介绍。

2. 初始化环境

创建索引:

PUT /news
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "ik_smart",
        "fields": {
          "kw": {
            "type": "completion",
            "analyzer": "keyword"
          },
          "py": {
            "type": "completion",
            "analyzer": "pinyin"
          }
        }
      },
      "body": {
        "type": "text",
        "analyzer": "ik_max_word",
        "fields": {
          "kw": {
            "type": "completion",
            "analyzer": "keyword"
          }
        }
      }
    }
  }
}

这里创建了一个新闻的索引。里面有两个字段titlebodytitle使用的是ik_smart分析器,body使用的是ik_max_word分析器。这里之所以要这样做后面再揭晓。

填充数据:

POST _bulk
{"index":{"_index":"news","_id":"1"}}
{"title":"乌鲁木齐惊现彩虹","body":"今日午后一场大雨过后,乌鲁木齐天空上出现一道彩虹"}
{"index":{"_index":"news","_id":"2"}}
{"title":"乌鲁木齐发展很好","body":"乌鲁木齐发展很好,很多美丽的景点,是个旅游的好去处"}
{"index":{"_index":"news","_id":"3"}}
{"title":"乌鲁木齐的景点","body":"乌鲁木齐的景点分布以乌鲁木齐为中心,东、南、西、北四个方向"}
{"index":{"_index":"news","_id":"4"}}
{"title":"南昌最好的大学江西师范大学","body":"江西师范大学是南昌一个知名大高校"}
{"index":{"_index":"news","_id":"5"}}
{"title":"江西师范大学","body":"江西师范大学简称“江西师大”,位于历史文化名城江西省会南昌市,是教育部、江西省人民政府共建高校"}
{"index":{"_index":"news","_id":"6"}}
{"title":"鄱阳湖","body":"鄱阳湖,古称彭蠡、彭蠡泽、彭泽,位于江西省北部,地处九江、南昌、上饶三市,是中国第一大淡水湖,也是中国第二大湖,仅次于青海湖"}

上面的新闻数据都是假数据,为了下面讲解方便而造的。

测试分析器效果:

GET news/_analyze
{
  "field": "title",
  "text": "乌鲁木齐惊现彩虹"
}

结果如下:

{
  "tokens" : [
    {
      "token" : "乌鲁木齐",
      "start_offset" : 0,
      "end_offset" : 4,
      "type" : "CN_WORD",
      "position" : 0
    },
    {
      "token" : "惊",
      "start_offset" : 4,
      "end_offset" : 5,
      "type" : "CN_CHAR",
      "position" : 1
    },
    {
      "token" : "现",
      "start_offset" : 5,
      "end_offset" : 6,
      "type" : "CN_CHAR",
      "position" : 2
    },
    {
      "token" : "彩虹",
      "start_offset" : 6,
      "end_offset" : 8,
      "type" : "CN_WORD",
      "position" : 3
    }
  ]
}

可以看到使用ik_smart分析器时,乌鲁木齐是一个长度为4的术语,这也是我为什么使用这个地名的原因。

3. Term suggester

Term suggester提示器会根据所提供的文本建议外观相似的术语,建议功能的部分功能仍在开发中

要怎么使用这个提示器呢,下面我就直接贴代码然后再讲解了。

GET news/_search
{
  "suggest": {
    "YOUR_SUGGESTION": {
      "text": "乌鲁木",
      "term": {
        "field": "title"
      }
    }
  }
}

上面时一个标准的简洁的使用方法。首先是suggest对象。然后下面有一个YOUR_SUGGESTION,这个我们可以自定义为自己喜欢的名字,他的作用只是一个标识,如果需要多个建议,只需要创建多个YOUR_SUGGESTION就可以。YOUR_SUGGESTION内部有text字段,一般是把用户输入数据放入其中。term表示他是一个术语建议器,其内部的field表示他提示依据的字段是title字段。

公共字段表:

字段字段含义
text建议文本是必需的选项,需要全局设置或针对每个建议设置(使用如下图)
field要从中获取候选建议的字段。这是必需的选项,需要全局设置或针对每个建议设置
analyer分析建议文本用的分析器。默认为建议字段的搜索分析器
size每个建议文本标记返回的最大更正数量
sore定义建议应该如何按建议文本项排序。两个可能的值有scorefrequency
suggest_mode建议模式控制控制文本术语在什么情况下应该被建议。可以指定三个可能的值
1. missing: 仅对索引中没有的建议文本术语提供建议。这是默认值
2. popular: 只建议出现在比原始建议文本术语更多的文档中的建议
2. always: 根据建议文本中的术语建议任何匹配的建议

text全局设置和针对每个建议设置

 

好大概结构已经讲解完了,我们来看看这个执行的结果吧。

{
  "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" : {
    "YOUR_SUGGESTION" : [
      {
        "text" : "乌",
        "offset" : 0,
        "length" : 1,
        "options" : [ ]
      },
      {
        "text" : "鲁",
        "offset" : 1,
        "length" : 1,
        "options" : [ ]
      },
      {
        "text" : "木",
        "offset" : 2,
        "length" : 1,
        "options" : [ ]
      }
    ]
  }
}

这个返回的结果我们只需要关注suggest字段就行了。这里的YOUR_SUGGESTION其实就请求时的自定义的YOUR_SUGGESTION,如果我们自定义为my_suggest_1,那这里也将是my_suggest_1。它作为一个标识。如果我们使用了多个YOUR_SUGGESTION,那返回的结果中,也将有多个,这个时候那个标识就起作用了,我们可以通过它来区分。

这里把我们的乌鲁木分成了三个字。这个三个字没有任何提示词。如果有提示词就会再options数组中展示,有时候提示有多个词匹配,所以是数组。

分成三个字是因为字段title使用的是ik_smart,所以我们将suggest的field指定为title时,suggest中的文本也会默认使用分析器ik_smart进行分析。而分析器认为乌鲁木并不是一个完整的词组,所以才会将其分成三个字。
为了将这三个字不分开,我们必须指定suggest中text使用的分词器,而不默认使用ik_smart。这时我就可以使用analyzer字段了。
使用方法如下:

GET news/_search
{
  "suggest": {
    "YOUR_SUGGESTION": {
      "text": "乌鲁木",
      "term": {
        "analyzer": "whitespace",
        "field": "title"
      }
    }
  }
}

请求返回结果如下:(只是截取了suggest部分,注意:后面都会这样)

{
 "suggest" : {
    "YOUR_SUGGESTION" : [
      {
        "text" : "乌鲁木",
        "offset" : 0,
        "length" : 3,
        "options" : [ ]
      }
    ]
  }
}

但是你可以看到,options中还是没有任何提示。这是什么情况呢?这里就有一个比较大的一个问题了。中文和英文的差异问题,术语提示默认长度,官方解释截图如下:

 这里默认设置了术语必须长度达到4个字符才会进行术语匹配。在英文中四个字符就是四个字母,要达到要求很简单的,但是中文四个字符就是四个字,四个字才能触发提示。
那我们测试一个将术语改为四个字,如下:

GET news/_search
{
  "suggest": {
    "YOUR_SUGGESTION": {
      "text": "乌鲁木大",
      "term": {
        "analyzer": "whitespace",
        "field": "title"
      }
    }
  }
}

响应结果:

{
  "suggest" : {
    "YOUR_SUGGESTION" : [
      {
        "text" : "乌鲁木大",
        "offset" : 0,
        "length" : 4,
        "options" : [
          {
            "text" : "乌鲁木齐",
            "score" : 0.75,
            "freq" : 3
          }
        ]
      }
    ]
  }
}

提示出现了,不过四个字才会提示有点坑爹。那我们把那个参数改成2个字试试。

GET news/_search
{
  "suggest": {
    "YOUR_SUGGESTION": {
      "text": "乌鲁木",
      "term": {
        "analyzer": "whitespace",
        "min_word_length": 2,
        "field": "title"
      }
    }
  }
}

响应结果:

{
  "suggest" : {
    "YOUR_SUGGESTION" : [
      {
        "text" : "乌鲁木",
        "offset" : 0,
        "length" : 3,
        "options" : [
          {
            "text" : "乌鲁木齐",
            "score" : 0.6666666,
            "freq" : 3
          }
        ]
      }
    ]
  }
}

术语建议依然会有提示,这里有一个问题,乌鲁木齐四个字我们发送的乌鲁木对了三个字,但是score字段只有0.666,本来应该是0.75才是,上面测试的乌鲁木大score值都是0.75。这说明缺少字,会影响score分值。

如果我们只用乌鲁两个字进行测试,那么score将会小于0.5,这就导致了无法出现提示了。但是如果我们使用乌鲁xx(x可以是不是空格字符的任意字符),那将会有建议出现。
下面开始检验:

GET news/_search
{
  "suggest": {
    "two_words": {
      "text": "乌鲁 乌鲁00 乌鲁000",
      "term": {
        "analyzer": "whitespace",
        "min_word_length": 2,
        "field": "title"
      }
    }
  }
}

响应结果如下:

{
  "suggest" : {
    "two_words" : [
      {
        "text" : "乌鲁",
        "offset" : 0,
        "length" : 2,
        "options" : [ ]
      },
      {
        "text" : "乌鲁00",
        "offset" : 3,
        "length" : 4,
        "options" : [
          {
            "text" : "乌鲁木齐",
            "score" : 0.5,
            "freq" : 3
          }
        ]
      },
      {
        "text" : "乌鲁000",
        "offset" : 8,
        "length" : 5,
        "options" : [ ]
      }
    ]
  }
}

测试说明字符少了或是多了都会影响分值的计算,分值少于0.5时,不会出现建议术语。

看到这里或许不用我说大家也知道了,这个术语建议在中文中并不好用,只能用于一些用户分好词以后的建议。比如这里我使用的分析器analyzerwhitespace,这就要求用户输入每一个术语时自己空格。这是不太友好的,如果使用ik_smart,他只会在乌鲁木齐完整词才会认为它是一个整体,但是一旦少了一个字,其他三个字就会被分开,这也是不行的。
对于英文我们可以直接使用standard分析器。但是中文不行。

下面我就把Term Suggester的其他可用的参数进行列举一下:

字段名称作用
max_edits表示被选为建议的edit distance的最大值,只能是1,2之间的数(可以是小数),默认是2,其他值会报错
prefix_length表示被选为建议的最小前缀字符的长度,默认为1,增加这个长度可以提高拼写检查的性能,通常拼写错误不会发生在术语的最前面(prefix_len参数已经丢弃)
min_word_length表示推荐文本的最小长度,默认为4(min_word_len参数已被丢弃)
shard_size设置从每个碎片检索的建议的最大数量。在reduce阶段,根据size选项只返回前N个建议。默认是和size选项一样(如果不设置shard_size)。将此值设置为高于size的值可能有助于获得更准确的文档拼写更正频率,但会以性能为代价。由于术语是在切分之间分区的,因此切分级别的文档拼写更正频率可能并不精确。增加这个值将使这些文档频率更加精确。
max_inspections表示一个因子,这个参数和shard_size参数相乘以便在碎片级别检查更多的候选者的拼写错误,可以提高以性能为代价的准确性,参数默认为5
min_doc_freq表示一个建议中应包含文档数目的最小限制,可以指定为一个确切的数或文档数的相对百分比,可以通过推荐高频术语来提高质量,min_doc_freq默认是0(即不开启此功能),如果将这个参数指定为一个大于1的值(不能是小数,当大于1时不能指定为小数),碎片级别的文档频率用于这个选项
max_term_freq表示推荐文本可以包含的文档数目的最大限制,可以是一个代表文档频率的确切值,也可以是一个相对百分数(比如0.4),如果指定为一个大于1的数(不可以指定为小数),默认是0.01f,这个参数可以用来排除高频术语的拼写检查,高频术语通常在前几个字符是拼写正确的以提高拼写检查的性能,碎片(分片)性能文档频率用于这个选项
string_distance表示一个字符串距离用于和推荐内容相比它们之间的相似性,这个参数可能的值有5个:
internal:表示默认的基于damerau_levenshtein算法,但在比较字符串距离内的索引已经做过高度优化
damerau_levenshtein:是一种基于Damerau-Levenshtein算法的字符串距离算法
levenshtein:是一种基于Levenshtein edit distance算法的字符串距离算法
jaro_winkler:是一种基于Jaro-Winkler算法的字符串距离算法
ngram:是一种基于字符连词的字符串距离算法

                                                         prefix_lenght作用举例

min_doc_freq作用举例

4. 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.

上面是对phrase suggester的官方解释,简单的来说,其实他的意思就是说phrase suggesterterm suggester相比,对建议的文本会参考上下文,也就是一个句子的其他token,不只是单纯的token距离匹配,它可以基于共生和频率选出更好的建议。

API例子

例子

可能有人会有疑问,为什么,这里中文也使用analyzer:whitespace?其实还是和之前说过的情况一样。因为索引中title字段使用的分析器是ik_smart,所以如果这里不指定默认就是和title字段一样的分析器,但是ik_smart分析器无法判断乌鲁木q是一个术语,他会将其拆分成乌,鲁,木,q,从而导致建议器无法提供任何建议。

看下面的请求:

GET news/_search
{
  "suggest": {
    "text": "乌1木q 现 虹",
    "simple_phrase": {
      "phrase": {
        "field": "title",
        "analyzer": "whitespace",
        "gram_size": 3,
        "direct_generator": [
          {
            "field": "title",
            "suggest_mode": "always"
          }
        ],
        "highlight": {
          "pre_tag": "<em>",
          "post_tag": "</em>"
        }
      }
    }
  }
}

响应结果:

{
 "suggest" : {
    "simple_phrase" : [
      {
        "text" : "乌1木q 现 虹",
        "offset" : 0,
        "length" : 8,
        "options" : [
          {
            "text" : "乌鲁木齐 现 虹",
            "highlighted" : "<em>乌鲁木齐</em> 现 虹",
            "score" : 0.008279981
          }
        ]
      }
    ]
  }

Api 例子:

GET news/_search
{
  "suggest": {
    "text": "乌1木q 现 虹",
    "simple_phrase": {
      "phrase": {
        "field": "title",
        "analyzer": "whitespace",
        "gram_size": 3,
        "direct_generator": [
          {
            "field": "title",
            "suggest_mode": "always"
          }
        ],
        "highlight": {
          "pre_tag": "<em>",
          "post_tag": "</em>"
        },
        "collate": {
          "query": {
            "source": {
              "match": {
                "{{field_name}}": "{{suggestion}}"
              }
            }
          },
          "params": {
            "field_name": "title"
          },
          "prune": true
        }
      }
    }
  }
}

响应结果:

{
   "suggest" : {
    "simple_phrase" : [
      {
        "text" : "乌1木q 现 虹",
        "offset" : 0,
        "length" : 8,
        "options" : [
          {
            "text" : "乌鲁木齐 现 虹",
            "highlighted" : "<em>乌鲁木齐</em> 现 虹",
            "score" : 0.008279981,
            "collate_match" : true
          }
        ]
      }
    ]
  }
}

其实Term suggesterPhrase suggester对于中文的支持并不好,这也是因为中文所有的词都是靠可分割的字组成的。这是中文的特性。

下面列举一下Phrase suggester可以用到的参数

字段作用
field用于作基于语言模式的连词查找字段,这个推荐器将会使用这个字段去获取修正分数的统计数据,这个字段是强制的
gram_size设置在field中连词的最大数值,如果这个字段不包含连词应该可以被忽略或者直接设置为1,注意ES会尝试基于特定的field字段检测连词的长度,这个字段用了shingle过滤器,如果没有显式指定那它的gram_size将会被设置为max_shingle_size
real_word_error_likelihood表示一个术语被拼错的甚至存在于字典中的可能性,默认是0.95对应于5%是真实单词是拼写错误(它的意思是我们插入ES中的数据也不是都是正确的,有5%是错误的)
confidence信任级别定义了一个影响为其他推荐词的阈值输入短语分数的因素,只有分数大于阈值的候选词会包含在结果中,比如设置为1.0将会返回分数大于输入短语的推荐词(这也是默认值),如果设置为0将会返回前N个候选词
max_errors为形成更正而被认为是拼写错误的术语的最大百分比。该方法接受范围为[0..1)的浮点值作为实际查询项的一部分,或者接受数字>=1作为查询项的绝对数量。默认设置为1.0,这意味着最多只返回一个拼写错误的术语。注意,将其设置得过高会对性能产生负面影响。建议使用1或2这样的低值;否则,花费在建议调用上的时间可能会超过执行查询所花费的时间
separator用于分隔双字母字段中的术语的分隔符。如果没有设置,将会默认使用空格字符用作分隔符。
size同(Term Suggester
analyzer同(Term Suggester
shard_size同(Term Suggester
text同(Term Suggester
highlight设置高亮推荐,如果不提供该参数将不会有返回highlighted字段;如果提供参数,那必须明确包含pre_tagpost_tag标签(用于包裹高亮内容),如果多个标记连续改变整个短语的改变标记包装而不是每个标记
collate对于每一个推荐词都做一次query查询,删除推荐词不存在匹配文档的索引,推荐词的校对查询仅仅可以在从本地碎片中获取的推荐词的碎片上执行,query参数必须指定,而且它可以被模板化,当前的推荐词可以作为{{suggestion}}自动使用(可以使用在查询中)。你还可以指定自己的模板params——suggestion值将被添加到指定的变量中,此外如果将返回所有推荐短语还可以指定一个prune来控制,当设置为true时推荐词将有一个额外的参数collate_match,如果相应的短语匹配到文档则为true,否则为falseprune默认值是false

平滑化模式(Smoothing Models)

Phrase suggester支持通过多种平滑模型以平衡低频短语(没有出现在索引中的短语)和高频连词(在索引中至少出现过一次)的权重,参数有:

  • stupid_backoff:一个简单的补偿模型,如果高阶数为0和折扣低阶语法模型常数因子,补偿作用将会发挥,默认discount是0.4,stupid_backoff是默认使用的模型
  • laplace:一个平滑模型,使用额外的平滑将常数添加所有以平衡权重,默认alpha是0.5
  • linear_interpolation:是一种基于用户提供的权值(lambdas)对一元、二元和三元图取加权平均值的平滑模型,线性插值模式没有提供任何默认值,要使用这种模型必须手动提供所有参数(包括trigram_lambdabigram_lambdaunigram_lambda

候选词生成器(Candidate Generators)

Phrase suggester使用候选生成器生成给定文本中每个项可能的项的列表。单个候选生成器类似于为文本中的每个单独的调用term suggester。生成器的输出随后与建议候选项中的候选项结合打分。目前只支持一种候选生成器,即direct_generator。建议API接受密钥直接生成器下的生成器列表;列表中的每个生成器都按原始文本中的每个项调用。

直接生成器(Direct Generators)

直接生成器支持以下参数:

字段作用
field要从中获取候选建议的字段。这是必需的选项,需要全局设置或按建议设置
size每个建议文本标记返回的最大更正
suggest_mode建议模式控制控制文本术语在什么情况下应该被建议。可以指定三个可能的值
1. missing: 仅对索引中没有的建议文本术语提供建议。这是默认值
2. popular: 只建议出现在比原始建议文本术语更多的文档中的建议
3. always: 根据建议文本中的术语建议任何匹配的建议
max_edits表示被选为建议的edit distance的最大值,只能是1,2之间的数(可以是小数),默认是2,其他值会报错
prefix_length表示被选为建议的最小前缀字符的长度,默认为1,增加这个长度可以提高拼写检查的性能,通常拼写错误不会发生在术语的最前面(prefix_len参数已经丢弃)
min_word_length表示推荐文本的最小长度,默认为4(min_word_len参数已被丢弃)
max_inspections表示一个因子,这个参数和shard_size参数相乘以便在碎片级别检查更多的候选者的拼写错误,可以提高以性能为代价的准确性,参数默认为5
min_doc_freq表示一个建议中应包含文档数目的最小限制,可以指定为一个确切的数或文档数的相对百分比,可以通过推荐高频术语来提高质量,==min_doc_freq==默认是0(即不开启此功能),如果将这个参数指定为一个大于1的值(不能是小数,当大于1时不能指定为小数),碎片级别的文档频率用于这个选项
max_term_freq表示推荐文本可以包含的文档数目的最大限制,可以是一个代表文档频率的确切值,也可以是一个相对百分数(比如0.4),如果指定为一个大于1的数(不可以指定为小数),默认是0.01f,这个参数可以用来排除高频术语的拼写检查,高频术语通常在前几个字符是拼写正确的以提高拼写检查的性能,碎片(分片)性能文档频率用于这个选项
pre_filter应用于传递给此候选生成器的每个令牌的筛选器(analyzer)。在生成候选标记之前,此筛选器将应用于原始标记。
post_filter一个过滤器(analyzer),在将生成的令牌传递给实际的短语评分器之前应用于它们。

5. completion suggester

Completion Suggester提供自动完成/随类型搜索的功能。这是一种导航特性,可以在用户键入时引导他们找到相关结果,提高搜索精度。它不是用来纠正拼写或做你想说的功能,如Term SuggesterPhrase Suggester
在理想情况下,自动完成功能应该和用户输入一样快,以便为用户已经输入的内容提供即时反馈。因此,Completion Suggester在速度上进行了优化。建议器使用支持快速查找的数据结构,但是构建成本很高,并且存储在内存中。

下面看这幅图:

这是用百度搜索有关es,提示图

在我们输入相应的关键词时,百度会自动帮助我们不全相关信息,这样不仅方便用户,而且提高了搜索的精度。
接下来然我们看看ESCompletion Suggester怎么做到上面的效果。

在我们最开始初始化数据时,设置了title的附加字段分别为kwpy,而且类型为completion,现在就是使用它们的时候了。
下面直接看Api使用例子:

GET news/_search
{
  "suggest": {
    "YOUR_SUGGESTION_KW": {
      "prefix": "鄱",
      "completion": {
        "field": "title.kw"
      }
    },
    "YOUR_SUGGESTION_PY": {
      "prefix": "鄱",
      "completion": {
        "field": "title.py"
      }
    }
  }
}

响应结果:

{
  "suggest" : {
    "YOUR_SUGGESTION_KW" : [
      {
        "text" : "鄱",
        "offset" : 0,
        "length" : 1,
        "options" : [
          {
            "text" : "鄱阳湖",
            "_index" : "news",
            "_type" : "_doc",
            "_id" : "6",
            "_score" : 1.0,
            "_source" : {
              "title" : "鄱阳湖",
              "body" : "鄱阳湖,古称彭蠡、彭蠡泽、彭泽,位于江西省北部,地处九江、南昌、上饶三市,是中国第一大淡水湖,也是中国第二大湖,仅次于青海湖"
            }
          }
        ]
      }
    ],
    "YOUR_SUGGESTION_PY" : [
      {
        "text" : "鄱",
        "offset" : 0,
        "length" : 1,
        "options" : [
          {
            "text" : "鄱阳湖",
            "_index" : "news",
            "_type" : "_doc",
            "_id" : "6",
            "_score" : 1.0,
            "_source" : {
              "title" : "鄱阳湖",
              "body" : "鄱阳湖,古称彭蠡、彭蠡泽、彭泽,位于江西省北部,地处九江、南昌、上饶三市,是中国第一大淡水湖,也是中国第二大湖,仅次于青海湖"
            }
          }
        ]
      }
    ]
  }
}

根据前缀就可以返回相应的结果,这里或许让小伙伴有一个疑问,title.kw使用的分析器(analyzer)是keyword。发送prefix="鄱",可以匹配鄱阳湖这是没有问题的,但是为什么title.py也能匹配到呢?title.py不是应该输入拼音才能匹配到吗?
其实是这样的,Completion Suggester也是会将发送过来的短句进行分析的。默认使用的分析器就是指定字段所使用的分析器,title.py使用的分析器是pinyin,所以prefix="鄱"会被分析成po然后再进行前缀匹配。就能匹配到鄱阳湖的拼音了。

为了检测上面的结论,可以使用下面的例子:

GET news/_search
{
  "suggest": {
    "YOUR_SUGGESTION_PY": {
      "prefix": "破杨虎",
      "completion": {
        "field": "title.py"
      }
    }
  }
}

返回的相应的结果:

{
  "suggest" : {
    "YOUR_SUGGESTION_PY" : [
      {
        "text" : "破杨虎",
        "offset" : 0,
        "length" : 3,
        "options" : [
          {
            "text" : "鄱阳湖",
            "_index" : "news",
            "_type" : "_doc",
            "_id" : "6",
            "_score" : 1.0,
            "_source" : {
              "title" : "鄱阳湖",
              "body" : "鄱阳湖,古称彭蠡、彭蠡泽、彭泽,位于江西省北部,地处九江、南昌、上饶三市,是中国第一大淡水湖,也是中国第二大湖,仅次于青海湖"
            }
          }
        ]
      }
    ]
  }
}

因为鄱阳湖破杨虎拼音一样所以用拼音也能将其匹配到。

下面列举一下Completion Suggester支持的参数:

参数名称作用
size返回建议的数量(默认为5)
skip_duplicates是否应该过滤重复的建议(默认为false)
field要在其上运行查询的字段名(必需的)

查询可以返回来自不同文档的重复建议。可以通过将skip duplicates设置为true来修改此行为。设置后,此选项将从结果中过滤出具有重复建议的文档

POST news/_doc/7
{
  "title": "鄱阳湖",
  "body": "我家在鄱阳湖"
}

POST news/_search
{
  "suggest": {
    "YOUR_SUGGESTION_1": {
      "text": "鄱阳",
      "completion": {
        "field": "title.kw"
      }
    },
    "YOUR_SUGGESTION_2": {
      "text": "鄱阳",
      "completion": {
        "field": "title.kw",
        "skip_duplicates": true
      }
    }
  }
}

响应结果:

{
  "suggest" : {
    "YOUR_SUGGESTION_1" : [
      {
        "text" : "鄱阳",
        "offset" : 0,
        "length" : 2,
        "options" : [
          {
            "text" : "鄱阳湖",
            "_index" : "news",
            "_type" : "_doc",
            "_id" : "6",
            "_score" : 1.0,
            "_source" : {
              "title" : "鄱阳湖",
              "body" : "鄱阳湖,古称彭蠡、彭蠡泽、彭泽,位于江西省北部,地处九江、南昌、上饶三市,是中国第一大淡水湖,也是中国第二大湖,仅次于青海湖"
            }
          },
          {
            "text" : "鄱阳湖",
            "_index" : "news",
            "_type" : "_doc",
            "_id" : "7",
            "_score" : 1.0,
            "_source" : {
              "title" : "鄱阳湖",
              "body" : "我家在鄱阳湖"
            }
          }
        ]
      }
    ],
    "YOUR_SUGGESTION_2" : [
      {
        "text" : "鄱阳",
        "offset" : 0,
        "length" : 2,
        "options" : [
          {
            "text" : "鄱阳湖",
            "_index" : "news",
            "_type" : "_doc",
            "_id" : "6",
            "_score" : 1.0,
            "_source" : {
              "title" : "鄱阳湖",
              "body" : "鄱阳湖,古称彭蠡、彭蠡泽、彭泽,位于江西省北部,地处九江、南昌、上饶三市,是中国第一大淡水湖,也是中国第二大湖,仅次于青海湖"
            }
          }
        ]
      }
    ]
  }
}

当设置为真时,这个选项会降低搜索速度,因为需要访问更多的建议才能找到顶部N

模糊搜索(Fuzzy queries)

完成建议器也支持模糊查询,这意味着你可以在你的搜索中有一个错误,但仍然可以得到结果

POST news/_search
{
  "suggest": {
    "YOUR_SUGGESTION": {
      "text": "鄱a",
      "completion": {
        "field": "title.kw",
        "fuzzy": {
          "fuzziness": 1
        }
      }
    }
  }
}
POST news/_search
{
  "suggest": {
    "YOUR_SUGGESTION": {
      "text": "1鄱1",
      "completion": {
        "field": "title.kw",
        "skip_duplicates": true,
        "fuzzy": {
          "prefix_length": 0,
          "fuzziness": 2
        }
      }
    }
  }
}

与查询前缀共享最长前缀的建议得分更高

模糊查询可以取特定的模糊参数。支持以下参数:

参数名称作用
fuzziness模糊因子,默认为自动。有关允许的设置,请参阅模糊
transpositions如果设置为真,转换将被视为一个更改,而不是两个,默认值为真
min_length返回模糊建议之前输入的最小长度,默认为3
prefix_length输入的最小长度默认为1,不检查模糊选项
unicode_aware如果为真,那么所有度量(如模糊编辑距离、换位和长度)都是以Unicode代码点而不是字节来度量的。这比原始字节稍微慢一些,因此默认将其设置为false

Elasticsearch:fuzzy 搜索 (模糊搜索)

正则查询(Regex queries)

完成提示符还支持正则表达式查询,这意味着可以将前缀表示为正则表达式

POST news/_search
{
  "suggest": {
    "YOUR_SUGGESTION": {
      "regex": "[p|w]y",
      "completion": {
        "field": "title.py"
      }
    }
  }
}
POST news/_search
{
  "suggest": {
    "YOUR_SUGGESTION": {
      "regex": "[p|w]",
      "completion": {
        "field": "title.py"
      }
    }
  }
}

正则表达式查询可以接受特定的正则表达式参数。支持以下参数:

参数名称作用
flags可能的标志是ALL(默认)、ANYSTRING、补、空、交集、INTERVAL或NONE。参见regexpi -syntax了解其含义
max_determinized_states正则表达式是危险的,因为它很容易意外地创建一个看起来无害的表达式,它需要指数级的内部确定自动机状态(以及相应的RAM和CPU)才能让Lucene执行。Lucene使用最大确定状态设置(默认值为10000)来防止这些情况发生。您可以提高这个限制以允许更复杂的正则表达式执行

当我们不仅需要自动完成,还需要将最新的热点信息排在上面,而不是按长度去排列怎么办。Completion suggester也是可以帮助我们搞定的。

要实现那个需求其实就是要我们能自定义建议的权重

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值