1.概念

1.补全api主要分为四类

  1. Term Suggester(纠错补全,输入错误的情况下补全正确的单词)
  2. Phrase Suggester(自动补全短语,输入一个单词补全整个短语)
  3. Completion Suggester(完成补全单词,输出如前半部分,补全整个单词)
  4. Context Suggester(上下文补全)

整体效果类似百度搜索,如图:

  

2.Term Suggester(纠错补全)

2.1.api

1.建立索引

PUT /book4
{
"mappings": {
"english": {
"properties": {
"passage": {
"type": "text"
}
}
}
}
}

2.插入数据

curl -H "Content-Type: application/json" -XPOST 'http:localhost:9200/_bulk' -d'
{ "index" : { "_index" : "book4", "_type" : "english" } }
{ "passage": "Lucene is cool"}
{ "index" : { "_index" : "book4", "_type" : "english" } }
{ "passage": "Elasticsearch builds on top of lucene"}
{ "index" : { "_index" : "book4", "_type" : "english" } }
{ "passage": "Elasticsearch rocks"}
{ "index" : { "_index" : "book4", "_type" : "english" } }
{ "passage": "Elastic is the company behind ELK stack"}
{ "index" : { "_index" : "book4", "_type" : "english" } }
{ "passage": "elk rocks"}
{ "index" : { "_index" : "book4", "_type" : "english" } }
{ "passage": "elasticsearch is rock solid"}
'

3.看下储存的分词有哪些

post /_analyze
{
"text": [
"Lucene is cool",
"Elasticsearch builds on top of lucene",
"Elasticsearch rocks",
"Elastic is the company behind ELK stack",
"elk rocks",
"elasticsearch is rock solid"
]
}

结果:

{
"tokens": [
{
"token": "lucene",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "is",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "cool",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "elasticsearch",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "builds",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "on",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "top",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "of",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "lucene",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "elasticsearch",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "rocks",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "elastic",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "is",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "the",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "company",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "behind",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "elk",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "stack",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "elk",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "rocks",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "elasticsearch",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "is",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "rock",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
},
{
"token": "solid",
"start_offset": ,
"end_offset": ,
"type": "<ALPHANUM>",
"position":
}
]
}

4.term suggest api(搜索单个字段)

搜索下试试,给出错误单词Elasticsearaach

POST /book4/_search
{
"suggest" : {
"my-suggestion" : {
"text" : "Elasticsearaach",
"term" : {
"field" : "passage",
     "suggest_mode": "popular"
}
}
}
}

response:

{
"took": ,
"timed_out": false,
"_shards": {
"total": ,
"successful": ,
"skipped": ,
"failed":
},
"hits": {
"total": ,
"max_score": ,
"hits": []
},
"suggest": {
"my-suggestion": [
{
"text": "elasticsearaach",
"offset": ,
"length": ,
"options": [
{
"text": "elasticsearch",
"score": 0.84615386,
"freq": 3
}
]
}
]
}
}

5.搜索多个字段分别给出提示:

POST _search
{
"suggest": {
"my-suggest-1" : {
"text" : "tring out Elasticsearch",
"term" : {
"field" : "message"
}
},
"my-suggest-2" : {
"text" : "kmichy",
"term" : {
"field" : "user"
}
}
}
}

term建议者提出基于编辑距离条款。在建议术语之前分析提供的建议文本。建议的术语是根据分析的建议文本标记提供的。该term建议者不走查询到的是是的请求部分。

常见建议选项:

text

建议文字。建议文本是必需的选项,需要全局或按建议设置。

field

从中获取候选建议的字段。这是一个必需的选项,需要全局设置或根据建议设置。

analyzer

用于分析建议文本的分析器。默认为建议字段的搜索分析器。

size

每个建议文本标记返回的最大更正。

sort

定义如何根据建议文本术语对建议进行排序。两个可能的值:

  • score:先按分数排序,然后按文档频率排序,再按术语本身排序。
  • frequency:首先按文档频率排序,然后按相似性分数排序,然后按术语本身排序。

suggest_mode

建议模式控制包含哪些建议或控制建议的文本术语,建议。可以指定三个可能的值:

  • missing:仅提供不在索引词典中,但是在原文档中的词。这是默认值。
  • popular:仅提供在索引词典中出现的词语。
  • always:索引词典中出没出现的词语都要给出建议。

其他术语建议选项:

lowercase_terms

在文本分析之后,建议文本术语小写。

max_edits

最大编辑距离候选建议可以具有以便被视为建议。只能是介于1和2之间的值。任何其他值都会导致抛出错误的请求错误。默认为2。

prefix_length

必须匹配的最小前缀字符的数量才是候选建议。默认为1.增加此数字可提高拼写检查性能。通常拼写错误不会出现在术语的开头。(旧名“prefix_len”已弃用)

min_word_length

建议文本术语必须具有的最小长度才能包含在内。默认为4.(旧名称“min_word_len”已弃用)

shard_size

设置从每个单独分片中检索的最大建议数。在减少阶段,仅根据size选项返回前N个建议。默认为该 size选项。将此值设置为高于该值的值size可能非常有用,以便以性能为代价获得更准确的拼写更正文档频率。由于术语在分片之间被划分,因此拼写校正频率的分片级文档可能不准确。增加这些将使这些文档频率更精确。

max_inspections

用于乘以的因子, shards_size以便在碎片级别上检查更多候选拼写更正。可以以性能为代价提高准确性。默认为5。

min_doc_freq

建议应出现的文档数量的最小阈值。可以指定为绝对数字或文档数量的相对百分比。这可以仅通过建议高频项来提高质量。默认为0f且未启用。如果指定的值大于1,则该数字不能是小数。分片级文档频率用于此选项。

max_term_freq

建议文本令牌可以存在的文档数量的最大阈值,以便包括在内。可以是表示文档频率的相对百分比数(例如0.4)或绝对数。如果指定的值大于1,则不能指定小数。默认为0.01f。这可用于排除高频术语的拼写检查。高频术语通常拼写正确,这也提高了拼写检查的性能。分片级文档频率用于此选项。

string_distance

用于比较类似建议术语的字符串距离实现。可以指定五个可能的值: internal- 默认值基于damerau_levenshtein,但高度优化用于比较索引中术语的字符串距离。damerau_levenshtein - 基于Damerau-Levenshtein算法的字符串距离算法。levenshtein - 基于Levenshtein编辑距离算法的字符串距离算法。 jaro_winkler - 基于Jaro-Winkler算法的字符串距离算法。 ngram - 基于字符n-gram的字符串距离算法。

官方api

2.phase sguesster:短语纠错

phrase 短语建议,在term的基础上,会考量多个term之间的关系,比如是否同时出现在索引的原文里,相邻程度,以及词频等

示例1:

POST book4/_search
{
  "suggest" : {
    "myss":{
      "text": "Elasticsearch rock",
      "phrase": {
        "field": "passage"
      }
    }
  }
}

{
"took": ,
"timed_out": false,
"_shards": {
"total": ,
"successful": ,
"skipped": ,
"failed":
},
"hits": {
"total": ,
"max_score": ,
"hits": []
},
"suggest": {
"myss": [
{
"text": "Elasticsearch rock",
"offset": ,
"length": ,
"options": [
{
"text": "elasticsearch rocks",
"score": 0.3467123
}
]
}
]
}
}

3. Completion suggester   自动补全

针对自动补全场景而设计的建议器。此场景下用户每输入一个字符的时候,就需要即时发送一次查询请求到后端查找匹配项,在用户输入速度较高的情况下对后端响应速度要求比较苛刻。因此实现上它和前面两个Suggester采用了不同的数据结构,索引并非通过倒排来完成,而是将analyze过的数据编码成FST和索引一起存放。对于一个open状态的索引,FST会被ES整个装载到内存里的,进行前缀查找速度极快。但是FST只能用于前缀查找,这也是Completion Suggester的局限所在

1.建立索引

POST /book5

{
"mappings": {
"music" : {
"properties" : {
"suggest" : {
"type" : "completion"
},
"title" : {
"type": "keyword"
}
}
}
}
}

插入数据:

POST /book5/music

{
"suggest":"test my book"
}

Input 指定输入词 Weight 指定排序值(可选)

PUT music/music/5nupmmUBYLvVFwGWH3cu?refresh
{
"suggest" : {
"input": [ "test", "book" ],
"weight" :
}
}

指定不同的排序值:

PUT music/_doc/6Hu2mmUBYLvVFwGWxXef?refresh
{
"suggest" : [
{
"input": "test",
"weight" :
},
{
"input": "good",
"weight" :
}
]}

示例1:查询建议根据前缀查询

POST book5/_search?pretty
{
"suggest": {
"song-suggest" : {
"prefix" : "te",
"completion" : {
"field" : "suggest"
}
}
}
}
{
"took": ,
"timed_out": false,
"_shards": {
"total": ,
"successful": ,
"skipped": ,
"failed":
},
"hits": {
"total": ,
"max_score": ,
"hits": []
},
"suggest": {
"song-suggest": [
{
"text": "te",
"offset": ,
"length": ,
"options": [
{
"text": "test my book1",
"_index": "book5",
"_type": "music",
"_id": "6Xu6mmUBYLvVFwGWpXeL",
"_score": ,
"_source": {
"suggest": "test my book1"
}
},
{
"text": "test my book1",
"_index": "book5",
"_type": "music",
"_id": "6nu8mmUBYLvVFwGWSndC",
"_score": ,
"_source": {
"suggest": "test my book1"
}
},
{
"text": "test my book1 english",
"_index": "book5",
"_type": "music",
"_id": "63u8mmUBYLvVFwGWZHdC",
"_score": ,
"_source": {
"suggest": "test my book1 english"
}
}
]
}
]
}
}

示例2:对建议查询结果去重

{
"suggest": {
"song-suggest" : {
"prefix" : "te",
"completion" : {
"field" : "suggest" ,
"skip_duplicates": true
}
}
}
}

示例3:查询建议文档存储短语

POST /book5/music/63u8mmUBYLvVFwGWZHdC?refresh
{
"suggest" : {
"input": [ "book1 english", "test english" ],
"weight" :
}
}

查询:

POST book5/_search?pretty
{
"suggest": {
"song-suggest" : {
"prefix" : "test",
"completion" : {
"field" : "suggest" ,
"skip_duplicates": true
}
}
}
}

结果:

{
"took": ,
"timed_out": false,
"_shards": {
"total": ,
"successful": ,
"skipped": ,
"failed":
},
"hits": {
"total": ,
"max_score": ,
"hits": []
},
"suggest": {
"song-suggest": [
{
"text": "test",
"offset": ,
"length": ,
"options": [
{
"text": "test english",
"_index": "book5",
"_type": "music",
"_id": "63u8mmUBYLvVFwGWZHdC",
"_score": ,
"_source": {
"suggest": {
"input": [
"book1 english",
"test english"
],
"weight":
}
}
},
{
"text": "test my book1",
"_index": "book5",
"_type": "music",
"_id": "6Xu6mmUBYLvVFwGWpXeL",
"_score": ,
"_source": {
"suggest": "test my book1"
}
}
]
}
]
}
}

4. 总结和建议

因此用好Completion Sugester并不是一件容易的事,实际应用开发过程中,需要根据数据特性和业务需要,灵活搭配analyzer和mapping参数,反复调试才可能获得理想的补全效果。

回到篇首搜索框的补全/纠错功能,如果用ES怎么实现呢?我能想到的一个的实现方式:

  1. 在用户刚开始输入的过程中,使用Completion Suggester进行关键词前缀匹配,刚开始匹配项会比较多,随着用户输入字符增多,匹配项越来越少。如果用户输入比较精准,可能Completion Suggester的结果已经够好,用户已经可以看到理想的备选项了。
  2. 如果Completion Suggester已经到了零匹配,那么可以猜测是否用户有输入错误,这时候可以尝试一下Phrase Suggester。
  3. 如果Phrase Suggester没有找到任何option,开始尝试term Suggester。

精准程度上(Precision)看: Completion >  Phrase > term, 而召回率上(Recall)则反之。从性能上看,Completion Suggester是最快的,如果能满足业务需求,只用Completion Suggester做前缀匹配是最理想的。 Phrase和Term由于是做倒排索引的搜索,相比较而言性能应该要低不少,应尽量控制suggester用到的索引的数据量,最理想的状况是经过一定时间预热后,索引可以全量map到内存。

ES系列十三、Elasticsearch Suggester API(自动补全)的更多相关文章

  1. 【Qt编程】基于Qt的词典开发系列<十四>自动补全功能

    最近写了一个查单词的类似有道词典的软件,里面就有一个自动补全功能(即当你输入一个字母时,就会出现几个候选项).这个自动补全功能十分常见,百度搜索关键词时就会出现.不过它们这些补全功能都是与你输入的进行 ...

  2. 第三百六十八节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现搜索的自动补全功能

    第三百六十八节,Python分布式爬虫打造搜索引擎Scrapy精讲—用Django实现搜索的自动补全功能 elasticsearch(搜索引擎)提供了自动补全接口 官方说明:https://www.e ...

  3. 四十七 Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现搜索的自动补全功能

    elasticsearch(搜索引擎)提供了自动补全接口 官方说明:https://www.elastic.co/guide/en/elasticsearch/reference/current/se ...

  4. java整合Elasticsearch,实现crud以及高级查询的分页,范围,排序功能,泰文分词器的使用,分组,最大,最小,平均值,以及自动补全功能

    //为index创建mapping,index相当于mysql的数据库,数据库里的表也要给各个字段创建类型,所以index也要给字段事先设置好类型: 使用postMan或者其他工具创建:(此处我使用p ...

  5. kubernetes系列(小知识):kubectl命令自动补全

    kubectl命令自动补全 linux系统 yum install -y bash-completion source /usr/share/bash-completion/completions/d ...

  6. bootstrap - typeahead自动补全插件

    $('#Sale').typeahead({ ajax: { url: '@Url.Action("../Contract/GetSale")', //timeout: 300, ...

  7. Visual Studio Code使用typings拓展自动补全功能

    转自:http://blog.csdn.net/liyijun4114/article/details/51658087 参考来源: 官方介绍: https://code.visualstudio.c ...

  8. StringBoot整合ELK实现日志收集和搜索自动补全功能(详细图文教程)

    @ 目录 StringBoot整合ELK实现日志收集和搜索自动补全功能(详细图文教程) 一.下载ELK的安装包上传并解压 1.Elasticsearch下载 2.Logstash下载 3.Kibana ...

  9. jQuery AutoComplete 自动补全

    jQuery.AutoComplete是一个基于jQuery的自动补全插件.借助于jQuery优秀的跨浏览器特性,可以兼容Chrome/IE/Firefox/Opera/Safari等多种浏览器. 特 ...

随机推荐

  1. 【LOJ#6374】网格(二项式反演,容斥)

    [LOJ#6374]网格(二项式反演,容斥) 题面 LOJ 要从\((0,0)\)走到\((T_x,T_y)\),每次走的都是一个向量\((x,y)\),要求\(0\le x\le M_x,0\le ...

  2. 【杂题1】USACO 2018 Open Contest-练习

    https://www.xoj.red/contests/show/1231 下面会写一些题目的解析什么的,当然不会粘贴题目只是简单提一下 (部分题目简单的题目就不概括了) 其实难度应该前面比较低. ...

  3. shell(2)-&& 与 || 逻辑或与非

    test 命令测试 -常见的测试类型–测试文件状态–字符串比较–整数值比较–逻辑测试&& 如果是“前面”(真),则“后面”[ -f /var/run/dhcpd.pid ] & ...

  4. cf827D Best Edge Weight (kruskal+倍增lca+并查集)

    先用kruskal处理出一个最小生成树 对于非树边,倍增找出两端点间的最大边权-1就是答案 对于树边,如果它能被替代,就要有一条非树边,两端点在树上的路径覆盖了这条树边,而且边权不大于这条树边 这里可 ...

  5. suoi63 树与路径 (倍增lca)

    发现对于某一个点它向上发的一条边,它被经过的次数就是这个点子树数量*不是它子树的数量 那就维护一个前缀和,然后每次拿两个端点和它们的lca的值加一加减一减,再乘上加上的值,就是这次修改后答案的增量 ( ...

  6. 火狐浏览器高度&制作简单万年历&弹出层

    浏览器高度: FireFox中: document.body.clientWidth ==> BODY对象宽度 document.body.clientHeight ==> BODY对象高 ...

  7. 初探ant-design(web版本)

    第一步安装ant-design插件 第二步查看项目目录 第三步运行项目 我们查看index.js文件 这个其实是Datepicker组件的展示效果 第四步我们按照下面的代码代替Index.js中的内容 ...

  8. Mac挂载虚拟机的共享文件夹

    说明:sshfs可以帮助本地mac访问虚拟机上的共享文件夹,从而操作虚拟机上的文件夹非常方便 1.安装sshfs sudo port install sshfs 2.使用,指定远程目录,到本地某一目录 ...

  9. 5个强大的Java分布式缓存框架

    在开发中大型Java软件项目时,很多Java架构师都会遇到数据库读写瓶颈,如果你在系统架构时并没有将缓存策略考虑进去,或者并没有选择更优的缓存策略,那么到时候重构起来将会是一个噩梦.本文主要是分享了5 ...

  10. 整理备忘一波liunx命令(持续更新)

    # 分区挂载 查看当前目录下的文件大小 du --max-depth= -h # 文件操作 # 编辑操作 #liunx 字体设置 苹果方字体下载安装 # 网洛端口 netstat命令各个参数说明如下: ...