输入关键字 抓取所有网页(美团CRM系统中的解决方案智能提示方案及需求分析)
优采云 发布时间: 2022-04-07 15:04输入关键字 抓取所有网页(美团CRM系统中的解决方案智能提示方案及需求分析)
背景
搜索关键词智能提示是搜索应用的标准配置。它的主要作用是避免用户输入错误的搜索词,引导用户到相应的关键词,提高用户的搜索体验。
美团CRM系统中商户数以百万计。为了让用户快速找到目标商户,我们实现了基于solrcloud的商户搜索模块。在搜索商家时,用户主要输入商家名称和商家地址进行搜索。为了提高用户的搜索体验和输入效率,本文实现了一种基于solr前缀匹配查询关键字的智能建议。
需求分析解决方案
方案1 Trie树+TopK算法 Trie树是字典树,也称为词搜索树或关键字树。它是一种树结构,是哈希树的一种变体。典型应用是对大量字符串(但不限于字符串)进行计数和排序,因此经常被搜索引擎系统用于文本词频统计。它的优点是:尽量减少不必要的字符串比较,查询效率高于哈希表。Trie 是一棵存储多个字符串的树。相邻节点之间的边代表一个字符,因此树的每个分支代表一个子串,而树的叶子节点代表完整的字符串。与普通树不同的是,相同的字符串前缀共享相同的分支。例如,给定一组单词 inn、int、at、age、adv、ant,我们可以得到以下 Trie:
从上图可以看出,当用户输入前缀i时,搜索框可能会显示“in”、“inn”、“int”等以i为前缀的关键词,然后当用户输入前缀a,在搜索框中,可能会有“吃”等以关键词为前缀的提示。这样一来,实现搜索引擎智能建议的第一步就明确了,就是用一个trie树来存储大量的字符串,并且在前缀固定的情况下,比较热的后缀是存储。
TopK算法用于解决统计热词问题。解决TopK问题主要有两种策略:hashmap统计+排序,堆排序hashmap统计:首先对这批海量数据进行预处理。具体方法是:维护一个HashTable,其Key为Query字符串,Value为Query出现的次数,即hash_map(Query, Value),每次读取一个Query,如果字符串不在Table中,则添加字符串,并将 Value 值设置为 1;如果字符串在 Table 中,只需对字符串的计数加一,最后使用 Hash 表完成 O(N) 时间复杂度的统计。堆排序:借助堆数据结构,求Top K,时间复杂度为N'logK。即使用堆结构,我们可以在日志顺序时间中查找和调整/移动。所以,
该方案存在的问题是: - 索引查询时必须将汉字转为拼音,查询完成后必须将拼音转为汉字显示,需要考虑数字和特殊字符。- 需要为拼音和缩写维护两棵Trie树。
解决方案2 Solr自带的Suggest智能提示 Solr是一个应用广泛的搜索引擎系统,它内置了一个智能提示功能,叫做Suggest模块。该模块可以选择根据提示词的文本进行智能提示,也支持通过为索引的某个字段建立索引词库来进行智能提示。(有关详细信息,请参阅 solr 的 wiki 页面)
该方案存在的问题是: - 返回结果是根据索引中字段的词频排序的,而不是用户搜索关键词的频率,所以一些热门关键词无法排在第一位。- 拼音提示、复音词和缩写仍然需要额外的索引字段。
方案3 Solrcloud构建单独的集合,使用solr前缀查询来实现如前所述,以上两种方案在实现上存在一些问题。Trie树+TopK算法在处理汉字建议时不是很优雅,需要维护两个Trie树实现起来比较复杂;Solr自带的suggest智能提示组件的问题是它使用了freq排序算法,返回的结果完全是根据索引中字符出现的次数,没有考虑用户搜索词出现的频率,所以有些流行单词无法排序。排名较高。因此,我们继续为这个问题找到一个更优雅的解决方案。
到目前为止,我们已经考虑使用 solr 前缀查询实现专门为关键字构建索引集合。solr中的copyField可以很好的解决我们同时索引多个字段(汉字、拼音、缩写)的需求,并且当字段的multiValued属性设置为true时,可以解决多音字组合的问题相同的关键字。配置如下:
schema.xml:
------------------multiValued表示字段是多值的-------------------------------------
kw
suggest
说明:
kw为原始关键字
pinyin和abbre的multiValued=true,在使用solrj建此索引时,定义成集合类型即可:如关键字“重庆”的pinyin字段为{chongqing,zhongqing}, abbre字段为{cq, zq}
kwfreq为用户搜索关键的频率,用于查询的时候排序
-------------------------------------------------------
------------------suggest_text----------------------------------
<filter class="solr.SynonymFilterFactory"
synonyms="synonyms.txt"
ignoreCase="true"
expand="true" />
KeywordTokenizerFactory:这个分词器不执行任何分词!整个字符流变成一个单一的标记。String 字段类型也有类似的作用,但它不能配置文本分析的其他处理组件,例如大小写转换。任何用于排序和大多数分面功能的索引字段,索引字段在原创字段值中只能有一个标记。
前缀查询构造:
private SolrQuery getSuggestQuery(String prefix, Integer limit) {
SolrQuery solrQuery = new SolrQuery();
StringBuilder sb = new StringBuilder();
sb.append(“suggest:").append(prefix).append("*");
solrQuery.setQuery(sb.toString());
solrQuery.addField("kw");
solrQuery.addField("kwfreq");
solrQuery.addSort("kwfreq", SolrQuery.ORDER.desc);
solrQuery.setStart(0);
solrQuery.setRows(limit);
return solrQuery;
}
结果如下图:
参考