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

Optimization 如何在海量数据集上实现自动完成,optimization,autocomplete,Optimization,Autocomplete,我正试图在我正在建设的一个网站上实现类似Google suggest的东西,我很好奇如何在一个非常大的数据集上进行操作。当然,如果你有1000个项目,你可以缓存这些项目,然后循环使用它们。但是当你有一百万件物品的时候,你怎么做呢?此外,假设项目不是一个单词。具体来说,潘多拉网站给我留下了深刻的印象。例如,如果您搜索“湿”它会返回“湿沙”,但它也会返回蟾蜍湿链轮。而且他们的自动完成速度很快。我的第一个想法是按照前两个字母对项目进行分组,这样您可以得到如下结果: Dictionary<stri

我正试图在我正在建设的一个网站上实现类似Google suggest的东西,我很好奇如何在一个非常大的数据集上进行操作。当然,如果你有1000个项目,你可以缓存这些项目,然后循环使用它们。但是当你有一百万件物品的时候,你怎么做呢?此外,假设项目不是一个单词。具体来说,潘多拉网站给我留下了深刻的印象。例如,如果您搜索“湿”它会返回“湿沙”,但它也会返回蟾蜍湿链轮。而且他们的自动完成速度很快。我的第一个想法是按照前两个字母对项目进行分组,这样您可以得到如下结果:

Dictionary<string,List<string>>
字典
其中键是前两个字母。没关系,但是如果我想做一些类似潘多拉的事情,允许用户看到与字符串中间匹配的结果,该怎么办?我的想法是:湿的永远不会匹配蟾蜍的湿链轮,因为它将在“TO”桶,而不是“WE”桶。那么,也许你可以把绳子分开,把“蟾蜍湿链轮”放在“TO”、“WE”和“SP”的桶里(去掉“the”),但是当你谈论一百万个条目时,可能每个条目都要说几个单词,这似乎很快就会消耗掉很多内存。好的,这是一个很长的问题。想法

正如我在文章中指出的,你应该使用类似于或的结构来搜索大文本中的模式

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

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


它真的是难以置信的快。要查找包含给定n个字符序列的所有文本,您必须检查最多n个节点,并在每个节点的子节点列表上执行搜索。根据子节点集合的实现(数组、列表、二叉树、跳过列表),您可能只需要5个搜索步骤(假设只使用不区分大小写的拉丁字母)就可以识别所需的子节点。插值排序对于较大的字母表和子节点较多的节点可能很有帮助,就像通常在根附近找到的那样。

我会使用沿a线的内容,并让每个叶节点的值成为包含叶节点表示的单词的可能性列表。您可以按照可能性的顺序对它们进行排序,或者根据用户在搜索框中输入的其他词对它们进行动态排序/过滤,等等。它将在合理的内存量内快速执行。

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

在算法上与您的请求无关,但请确保在按下键后有200毫秒或更长的延迟(滞后),以便确保用户在发出异步请求之前已停止键入。这样可以减少对服务器的冗余http请求。

不要尝试自己实现这一点(除非你只是好奇)。使用Lucene或Endeca之类的工具-这将节省您的时间和头发。

如果您不需要trie,并且希望从字符串中间添加内容,通常需要运行某种编辑距离函数(levenshtein distance),该函数将为您提供一个数字,指示两个字符串的匹配程度。这不是一个特别有效的算法,但是对于像单词这样的东西来说并不重要,因为它们相对较短。如果对8000个字符串进行比较,可能需要几秒钟的时间。我知道大多数语言都有一个实现,或者你可以在互联网上很容易地找到它的代码/伪代码。

我正是为这个场景构建的

注册一个私人索引,然后, 上传你的文件

在文档“纽约”上使用curl上传示例:

为所有文档编制索引后,要获取自动完成建议,请使用:

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

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

Trie非常适合在字符串开头查找匹配项。然而,对于我当前的数据集,删除第一个字符然后插入的过程并没有很好地结束,只是开始使用太多的内存:在数据集完成一半之前>1 gig。可能是过早优化的情况,当我只是运行一个简单的“包含”搜索时,运行时间不到100毫秒。Lucene看起来也很酷,所以我可以试试看。另一个想法是使用trie和NaiveSearch的组合。从trie开始,如果少于20个以匹配项开始,则返回NaiveSearch。为什么我只能插入300个字符??!标准的Trie非常占用内存,对于较大的集合,您需要使用压缩的Trie,这将大大减少内存占用。其他优化包括节点值的惰性初始化和子/值集的正确数据结构。不久前,我创建了一个能够处理非常大的数据集(10000000+),并能高效地回答精确和近似的搜索。我喜欢@Daniel answer。Lucene看起来真的很酷,谢谢你的建议!但是,是的,我当然好奇!:)你能给出一些关于你的数据的数字吗?多少根绳子?平均长度和平均字数?哪种语言?目前有496000个字符串。平均长度为14个字符。平均字数2.3。C#。哦,还有一些非ascii字符,比如Л和ЛI
http://suggest.autocompleteapi.com/[YourAccountKey]/[FieldName]?prefix=new