Dictionary 在一本大词典中查找一个单词的存在

Dictionary 在一本大词典中查找一个单词的存在,dictionary,Dictionary,假设我有一个包含2亿个单词的大字典,我的函数需要检查字典中是否存在任何给定的单词,最快的方法是什么?你不能将字典存储在内存中,因为你只有1GB的内存。您可以将其存储在数据库中,但是如果不进行任何优化,查询它的速度仍然非常慢。因为没有足够的资源,所以无法索引完整单词 编辑:除了下面提到的文件优化方法外,还有数据库优化吗?我在考虑创建部分索引,比如说,对于单词中的每两个字母,我创建一个索引。这会加速db查询吗?使用Boyer–Moore字符串搜索算法 如果没有索引,只需使用流即可 有时候,最简单的解

假设我有一个包含2亿个单词的大字典,我的函数需要检查字典中是否存在任何给定的单词,最快的方法是什么?你不能将字典存储在内存中,因为你只有1GB的内存。您可以将其存储在数据库中,但是如果不进行任何优化,查询它的速度仍然非常慢。因为没有足够的资源,所以无法索引完整单词


编辑:除了下面提到的文件优化方法外,还有数据库优化吗?我在考虑创建部分索引,比如说,对于单词中的每两个字母,我创建一个索引。这会加速db查询吗?

使用Boyer–Moore字符串搜索算法


如果没有索引,只需使用流即可

有时候,最简单的解决方案就是最好的

   public Int32 IndexOf(FileStream file, Byte[] ascii_bytes, Int32 start_index)
   {
       Int32 index = -1;
       {
           Int32 current = 0;
           Int64 original_index = 0;
           Boolean found = true;

           file.Position = start_index;
           current = file.ReadByte();
           while (current >= 0)
           {
               if ((Byte)current == ascii_bytes[0])
               {
                   found = true;
                   original_index = file.Position - 1;
                   for (Int32 i = 1; (i < ascii_bytes.Length && current > 0); i++)
                   {
                       current = file.ReadByte();
                       if ((Byte)current != ascii_bytes[i])
                       {
                           file.Position--;
                           found = false;
                           break;
                       }
                   }

                   if (found)
                   {
                       file.Position = original_index;
                       index = (Int32)original_index;
                       break;
                   }
               }
               current = file.ReadByte();
           }
       }
       return index;
   }
public Int32 IndexOf(文件流文件,字节[]ascii\u字节,Int32 start\u索引)
{
Int32指数=-1;
{
Int32电流=0;
Int64原始索引=0;
布尔值=真;
file.Position=start\u索引;
当前=file.ReadByte();
而(当前>=0)
{
如果((字节)当前==ascii_字节[0])
{
发现=真;
原始索引=file.Position-1;
对于(Int32 i=1;(i0);i++)
{
当前=file.ReadByte();
如果((字节)当前!=ascii_字节[i])
{
file.Position--;
发现=错误;
打破
}
}
如果(找到)
{
file.Position=原始索引;
索引=(Int32)原始索引;
打破
}
}
当前=file.ReadByte();
}
}
收益指数;
}
二进制搜索 假设字典中的单词按字母顺序排列,我会尝试修改。通过跳转到文件中的中点位置并查看其中的单词来分割和征服文件。如果猜测为“高”,请将较低的部分一分为二,然后重试,直到没有可尝试的文件位置或找到单词为止

(例如,跳转到文件位置后,需要前后扫描以找到跳转到的单词的边界。)

您可以通过根据单词的第一个字母猜出一个位置块来优化它。例如,如果单词以“c”开头,请在文件的3/26部分开始搜索。不过,事实上,我认为这一早期的猜测总体上只会产生微不足道的影响

其他优化可能包括保留索引的一小部分。例如,保留以字母表中每个字母开头的第一个单词的索引,或保留以每个可能的两个字母组合开头的每个单词的索引。这将允许您立即缩小搜索区域


O(logn)这是一个典型的应用程序用例。Bloom筛选器是一种概率数据结构,针对成员资格测试进行了优化(“X是此集合的成员吗?”),并提供O(1)查找。作为交换,你引入了一个任意小的误报概率——也就是说,过滤器会说一个特定的单词存在,但它实际上不存在。你使用的内存越多,这个概率就越小。然而,错误否定的概率为零:如果一个单词确实存在,过滤器将永远不会说它不存在

在您的特定情况下,使用80亿位(1GB),您可以获得比每100000000次试验中的1略高的假阳性率。这是一个极低的假阳性率。如果你查找了2亿个随机字符串,你从来没有碰到过一个假阳性的概率大约是82%

这不需要对字典进行排序,节省空间,并且不需要数据库或其他辅助存储结构。总的来说,它可能是满足您需求的好选择。

假设:

  • 在一个进程的生命周期中,您将多次搜索一个单词(而不是每次查找单词时都启动一个进程)
  • 文件已排序
  • 您可以对数据进行部分索引,占用大部分可用内存:使用B-树或排序数组(后者更节省空间,但需要单个连续块;此外,B-树要求您存储块的结束位置,而数组则不存储)。留出足够的内存空间,以便从文件中加载单个词块。在索引(树遍历或二进制搜索)中搜索将包含单词的块。从部分索引中找到特定块后,将相应的块从文件加载到内存中,并对其执行二进制搜索

    如果需要额外的内存,可以从索引中丢弃一些元素。使用该数组,可以使用以下伪C伪代码将索引减少到n个元素:

    struct chunk {
        string word;
        int start;
    };
    chunk index[];
    d = index.length / n;
    for (i=0;i<n; ++i) {
        index[i] = index[i*d];
    }
    realloc(index, sizeof(chunk) * n);
    
    struct chunk{
    字符串字;
    int启动;
    };
    组块索引[];
    d=索引长度/n;
    
    对于(i=0;i经典的单词查找问题可以使用一个有效的解决。不幸的是,正如您所提到的,您不能将所有需要的数据存储在内存中,但这不应该阻止您使用Trie来减少搜索空间。假设您不在Trie中存储整个单词集,而是只存储初始段,而您的d节点指向数据库中易于(快速)搜索的小型数据集合。

    如果某些单词是