高端移动网站建设,详情页模板哪个网站好,南宁房产信息网,小型教育网站开发与设计什么是自动补全#xff08;autocomplete#xff09;功能呢#xff1f;我们举一个很常见的例子。 每当你去谷歌并开始打字时#xff0c;就会出现一个下拉列表#xff0c;其中列出了建议。 这些建议与查询相关并帮助用户完成查询。 Autocomplete 正如维基百科所说的#xf…什么是自动补全autocomplete功能呢我们举一个很常见的例子。 每当你去谷歌并开始打字时就会出现一个下拉列表其中列出了建议。 这些建议与查询相关并帮助用户完成查询。 Autocomplete 正如维基百科所说的 Autocomplete 或单词完成是一个功能应用程序预测使用的其余单词正在键入 它也知道你键入或键入前方搜索。 它通过提示用户在键入文本的可能性和替代方案来帮助他们导航或指导用户。 它减少用户在执行任何搜索操作之前需要输入的字符数量从而增强用户的搜索体验。
可以通过使用任何数据库来实现 Autocomplete。 在这篇文章中我们将使用 Elasticsearch 构建自动补全功能。
Elasticsearch 是免费及开发分布式和基于JSON的搜索引擎建立在Lucene的顶部。更多关于 Elasticsearch 的介绍请阅读文章 “Elasticsearch 简介”。 方法
在 Elasticsearch 中可能有多种构建自动完成功能的方法。 我们将讨论以下方法。
Prefix queryEdge ngramCompletion suggesterPrefiex query
这种方法涉及使用针对自定义字段的前缀查询prefix query。 该字段的值可以作为 keyword 存储因此将多个 terms单词存储在一起作为一个术语。 可以使用关键字分词器keyword tokenizer来完成这一点。 这种方法遭受了缺点
由于只支持词首匹配不能匹配正文中间的 query。这种类型的查询未针对大型数据集进行优化可能会导致延迟增加。由于这是一个查询因此不会过滤掉重复的结果。 处理此方法的一种解决方法是使用聚合查询对结果进行分组然后过滤掉结果。 这涉及服务器端的一些处理Edge Ngrams
有关 edge ngrams 的介绍请参阅之前的文章 “Elasticsearch: Ngrams, edge ngrams, and shingles”。
这种方法涉及在索引和搜索时使用不同的分析器。 索引文档时可以应用带有 edge n-gram 过滤器的自定义分析器。 在搜索时可以应用标准分析器。 这可以防止查询被拆分。
Edge N-gram tokeniser 首先将文本分解为自定义字符空格、特殊字符等上的单词然后仅从字符串的开头保留 n-gram。
这种方法也适用于匹配文本中间的查询。 这种方法通常查询速度很快但可能会导致索引速度变慢和索引存储量变大。 Completion suggester
Elasticsearch 附带一个名为 Completion Suggester 的内部解决方案。 它使用称为有限状态传感器 (Finite State Transducer - FST) 的内存数据结构。 Elasticsearch 以每个段为基础存储 FST这意味着建议会随着更多新节点的添加而水平扩展。
实施 Completion Suggester 时要记住的一些事情
Autosuggest 项应将 completion 类型作为其字段类型。输入字段可以为单个术语具有各种规范名称或别名。可以为每个文档定义权重以控制它们的排名。以小写形式存储所有术语有助于不区分大小写的匹配。可以启用上下文 suggesters 以支持按特定标准进行过滤或提升。
这种方法是实现自动完成功能的理想方法但是它也有一些缺点
匹配总是从文本的开头开始。 所以在 movies 数据集中搜索 america 不会产生任何结果。 一种克服方法是在空格上标记输入文本并将所有短语保留为规范名称。 这样 Captain America: Civil War内战将被存储为
Captain America: Civil War
America: Civil War
Civil War
War
不支持突出highlight显示匹配的词。
没有可用的排序机制。 对建议进行排序的唯一方法是通过权重。 当需要任何自定义排序如字母排序或按上下文排序时这会产生问题。 实现
让我们在 Elasticsearch 中实现上述方法。 我们将使用 movies 数据来构建我们的示例索引。 为了便于参考我们使用如下的命令来创建 movies 索引
PUT movies
{settings: {index: {analysis: {filter: {},analyzer: {keyword_analyzer: {filter: [lowercase,asciifolding,trim],char_filter: [],type: custom,tokenizer: keyword},edge_ngram_analyzer: {filter: [lowercase],tokenizer: edge_ngram_tokenizer},edge_ngram_search_analyzer: {tokenizer: lowercase}},tokenizer: {edge_ngram_tokenizer: {type: edge_ngram,min_gram: 2,max_gram: 5,token_chars: [letter]}}}}},mappings: {properties: {name: {type: text,fields: {keywordstring: {type: text,analyzer: keyword_analyzer},edgengram: {type: text,analyzer: edge_ngram_analyzer,search_analyzer: edge_ngram_search_analyzer},completion: {type: completion}},analyzer: standard}}}
}
如果我们看到映射我们会发现 name 是一个 multi-fields 字段其中包含多个字段每个字段都以不同的方式进行分析。
使用关键字分词器分析 Fieldname.keywordstring因此它将用于前缀查询方法字段 name.edgengram 使用 Edge Ngram 分词器进行分析因此它将用于 Edge Ngram 方法。Field name.completion 存储为 completion 类型因此它将用于 Completion Suggester。
我们使用如下命令索引所有的电影
POST movies/_bulk
{ index : {_id : 1} }
{ name : Spider-Man: Homecoming }
{ index : {_id : 2} }
{ name : Ant-man and the Wasp }
{ index : {_id : 3} }
{ name : Avengers: Infinity War Part 2 }
{ index : {_id : 4} }
{ name : Captain Marvel }
{ index : {_id : 5} }
{ name : Black Panther }
{ index : {_id : 6} }
{ name : Avengers: Infinity War }
{ index : {_id : 7} }
{ name : Thor: Ragnarok }
{ index : {_id : 8} }
{ name : Guardians of the Galaxy Vol 2 }
{ index : {_id : 9} }
{ name : Doctor Strange }
{ index : {_id : 10} }
{ name : Captain America: Civil War }
{ index : {_id : 11} }
{ name : Ant-Man }
{ index : {_id : 12} }
{ name : Avengers: Age of Ultron }
{ index : {_id : 13} }
{ name : Guardians of the Galaxy }
{ index : {_id : 14} }
{ name : Captain America: The Winter Soldier }
{ index : {_id : 15} }
{ name : Thor: The Dark World }
{ index : {_id : 16} }
{ name : Iron Man 3 }
{ index : {_id : 17} }
{ name : Marvel’s The Avengers }
{ index : {_id : 18} }
{ name : Captain America: The First Avenger }
{ index : {_id : 19} }
{ name : Thor }
{ index : {_id : 20} }
{ name : Iron Man 2 }
{ index : {_id : 21} }
{ name : The Incredible Hulk }
{ index : {_id : 22} }
{ name : Iron Man }
让我们从 prefix query 方法开始尝试查找以 th 开头的电影。
查询将是
GET movies/_search?filter_path**.hits
{query: {prefix: {name.keywordstring: {value: th}}}
}
查询的结果是
{hits: {hits: [{_index: movies,_id: 7,_score: 1,_source: {name: Thor: Ragnarok}},{_index: movies,_id: 15,_score: 1,_source: {name: Thor: The Dark World}},{_index: movies,_id: 19,_score: 1,_source: {name: Thor}},{_index: movies,_id: 21,_score: 1,_source: {name: The Incredible Hulk}}]}
}
结果是公平的但是像 Captain America: The Winter SoldierGuardians of the Galaxy 这样的电影被遗漏了因为前缀查询只匹配文本的开头而不是中间。
让我们尝试寻找另一部以 am 开头的电影。
GET movies/_search?filter_path**.hits
{query: {prefix: {name.keywordstring: {value: am}}}
}
这里我们没有得到任何结果尽管 Captain America 满足这个条件。 这就印证了Prefix query 不能用于正文中间匹配的一点。
让我们运行相同的搜索但使用 Edge Ngram 方法。
GET movies/_search?filter_path**.hits
{query: {match: {name.edgengram: am}}
}
上面运行的结果是
{hits: {hits: [{_index: movies,_id: 10,_score: 1.5922177,_source: {name: Captain America: Civil War}},{_index: movies,_id: 14,_score: 1.3930962,_source: {name: Captain America: The Winter Soldier}},{_index: movies,_id: 18,_score: 1.3930962,_source: {name: Captain America: The First Avenger}}]}
}
让我们再次尝试寻找 Captain America但这次使用更大的短语 captain america the
GET movies/_search?filter_path**.hits
{query: {match: {name.edgengram: captain america the}}
}
使用 Edge N-gram 方法我们得到以下电影
{hits: {hits: [{_index: movies,_id: 21,_score: 1.0249562,_source: {name: The Incredible Hulk}},{_index: movies,_id: 17,_score: 0.9822227,_source: {name: Marvel’s The Avengers}},{_index: movies,_id: 2,_score: 0.94290996,_source: {name: Ant-man and the Wasp}},{_index: movies,_id: 13,_score: 0.94290996,_source: {name: Guardians of the Galaxy}},{_index: movies,_id: 15,_score: 0.906623,_source: {name: Thor: The Dark World}},{_index: movies,_id: 8,_score: 0.8730254,_source: {name: Guardians of the Galaxy Vol 2}},{_index: movies,_id: 14,_score: 0.7365507,_source: {name: Captain America: The Winter Soldier}},{_index: movies,_id: 18,_score: 0.7365507,_source: {name: Captain America: The First Avenger}}]}
}
如果我们观察我们的短语只有两个建议是有意义的。 匹配这么多术语的原因是 match 子句的功能。 匹配包括所有包含 captain OR america OR the 的文件。 由于该字段是使用 ngram 分析的因此也会包含更多建议如果存在。
让我们尝试使用针对相同短语 captain america the 的 suggest 查询。 建议查询的编写方式略有不同。
GET movies/_search?filter_pathsuggest
{suggest: {movie-suggest: {prefix: captain america the,completion: {field: name.completion}}}
}
结果我们得到以下电影
{suggest: {movie-suggest: [{text: captain america the,offset: 0,length: 19,options: [{text: Captain America: The First Avenger,_index: movies,_id: 18,_score: 1,_source: {name: Captain America: The First Avenger}},{text: Captain America: The Winter Soldier,_index: movies,_id: 14,_score: 1,_source: {name: Captain America: The Winter Soldier}}]}]}
}
让我们尝试相同的查询但这次使用了错别字 captain america the。
GET movies/_search?filter_pathsuggest
{suggest: {movie-suggest: {prefix: captain amrica the,completion: {field: name.completion}}}
}
上面的电影建议没有返回结果因为不支持模糊性。 我们可以通过以下方式更新查询以包含对模糊性的支持
GET movies/_search?filter_pathsuggest
{suggest: {movie-suggest: {prefix: captain amrica the,completion: {field: name.completion,fuzzy: {fuzziness: 1}}}}
}
以上查询返回以下结果
{suggest: {movie-suggest: [{text: captain amrica the,offset: 0,length: 18,options: [{text: Captain America: The First Avenger,_index: movies,_id: 18,_score: 10,_source: {name: Captain America: The First Avenger}},{text: Captain America: The Winter Soldier,_index: movies,_id: 14,_score: 10,_source: {name: Captain America: The Winter Soldier}}]}]}
} 结论
可以使用多种方法在 ElasticSearch 中实现自动完成功能。 Completion Suggester 涵盖了实现功能齐全且快速的自动完成所需的大多数情况。