如何在海量数据集上实现自动完成

时间:2009-03-24 19:53:19

标签: optimization autocomplete

我正在尝试在我正在构建的网站上实施Google建议的内容,并且很好奇如何在非常大的数据集上进行操作。当然,如果您有1000个项目,则缓存项目并循环浏览它们。但是当你拥有一百万件物品时,你如何去做呢?此外,假设项目不是一个单词。具体来说,我对Pandora.com印象非常深刻。例如,如果你搜索“湿”,它会带回“湿沙”,但它也会带回Toad The Wet Sprocket。他们的自动完成功能很快。我的第一个想法是按前两个字母对项目进行分组,所以你会有类似的东西:

Dictionary<string,List<string>>

其中键是前两个字母。那没关系,但是如果我想做类似Pandora的事情并允许用户看到与字符串中间匹配的结果呢?根据我的想法:Wet永远不会匹配Toad the Wet Sprocket,因为它将在“TO”桶而不是“WE”桶中。那么也许你可以分裂字符串和“Toad the Wet Sprocket”进入“TO”,“WE”和“SP”桶(删除单词“THE”),但是当你在谈论一百万条可能不得不说几句话,似乎你很快就开始耗费大量的记忆。好的,这是一个很长的问题。思考?

7 个答案:

答案 0 :(得分:27)

正如我在How to implement incremental search on a list中指出的那样,你应该使用像TriePatricia trie这样的结构来搜索大文本中的模式。

为了发现某些文本中间的模式,有一个简单的解决方案。我不确定它是否是最有效的解决方案,但我通常按如下方式进行。

当我在Trie中插入一些新文本时,我只是插入它,然后删除第一个字符,再次插入,删除第二个字符,再次插入......依此类推,直到整个文本被消耗掉。然后,您只需从根中搜索一次,即可发现每个插入文本的每个子字符串。产生的结构称为Suffix Tree,并且有很多可用的优化。

这真是令人难以置信的快速。要查找包含给定n个字符序列的所有文本,您必须检查最多n个节点,并对每个节点的子列表执行搜索。根据子节点集合的实现(数组,列表,二叉树,跳过列表),您可能能够识别所需的子节点,只需5个搜索步骤,仅假设不区分大小写的拉丁字母。插值排序可能对大型字母表和具有许多子节点的节点有帮助,这些子节点通常位于根目录附近。

答案 1 :(得分:9)

不要试图自己实现这个(除非你只是好奇)。使用像Lucene或Endeca这样的东西 - 它可以节省你的时间和头发。

答案 2 :(得分:5)

与您所询问的内容没有算法相关,但请确保在kaypress之后有200ms或更长的延迟(滞后),以确保用户在发出异步请求之前已停止输入。这样您就可以减少对服务器的冗余http请求。

答案 3 :(得分:2)

我会使用trie的行,并使每个叶节点的值成为包含叶节点所代表的单词的可能性列表。您可以按照可能性的顺序对它们进行排序,或者根据用户在搜索框中输入的其他单词对它们进行动态排序/过滤等。它将在非常快速的情况下以合理的RAM量执行。

答案 4 :(得分:1)

您将项目保留在服务器端(如果数据集非常庞大且复杂,可能在数据库中),并从客户端的浏览器发送AJAX调用,使用json / xml返回结果。您可以执行此操作以响应用户键入或使用计时器。

答案 5 :(得分:1)

如果你不想要一个特里,并且你想要从字符串中间填充东西,你通常想要运行某种编辑距离函数(levenshtein距离),它会给你一个数字,表示2个字符串的匹配程度。它不是一种特别有效的算法,但对于像文字这样的东西来说并不重要,因为它们相对较短。如果你在类似的8​​000个字符串上运行比较,它可能需要几秒钟。我知道大多数语言都有实现,或者你可以在互联网上轻松找到代码/伪代码。

答案 6 :(得分:0)

我为这个场景准确地构建了AutoCompleteAPI

注册以获取私人索引,然后, 上传你的文件。

使用curl对文档“纽约”进行上传示例:

curl -X PUT -H "Content-Type: application/json" -H "Authorization: [YourSecretKey]" -d '{
"key": "New York",
"input": "New York"
}' "http://suggest.autocompleteapi.com/[YourAccountKey]/[FieldName]"

索引所有文档后,要获取自动填充建议,请使用:

http://suggest.autocompleteapi.com/[YourAccountKey]/[FieldName]?prefix=new

您可以使用任何客户端自动填充库向用户显示这些结果。

相关问题