Sql server 需要输入数据库设计方法:为每个文本文件的单词编制索引,记住位置

Sql server 需要输入数据库设计方法:为每个文本文件的单词编制索引,记住位置,sql-server,database-design,Sql Server,Database Design,我有以下设计问题: 假设我有100万个大小约为10KB的纯文本文件。我的目标是设计一种方法来存储所有单词的索引,这样我就可以将每个单词链接到一个特定的文本文件以及单词在该文件中的位置 例如: Text file X contents: "The quick brown fox jumps over the lazy dog" 0 1 2 3 4 5 6 7 8 Text file Y contents

我有以下设计问题:

假设我有100万个大小约为10KB的纯文本文件。我的目标是设计一种方法来存储所有单词的索引,这样我就可以将每个单词链接到一个特定的文本文件以及单词在该文件中的位置

例如:

Text file X contents: "The quick brown fox jumps over the lazy dog"
                       0   1     2     3   4     5    6   7    8

Text file Y contents: "Now is the time for all good men"
                       0   1  2   3    4   5   6    7
我想大致存储以下内容:

the   => {X,0}, {X,6}, {Y,2}
quick => {X,1}
is    => {Y,1}
.... and so on
显然,实际上我并没有索引纯文本文件,我的索引器是一个多线程C#应用程序,它将输入提取到术语“file”、“word”、“position”。我无法创建一个典型的查找表集,因为行数很容易会超过20亿

我最初的想法是将成对的{message,position}存储在一个文本块中,该文本块的主键是word本身。然而,使用这个解决方案,我担心当我的所有线程都试图用新的{message,position}对更新“the”的行时,会出现巨大的争用

我被锁定在我的环境SQL Server Express 2012中,所以让我们来看看我们现有的环境。 我可以对数据库本身做任何事情,事实上,我的应用程序将数据库创建为正常工作流程的一部分,因此,如果需要,我可以部署CLR存储过程


想法?

为了扔掉一些东西,创建一个表,每个文件有一行。使用
xml
列存储文件中出现的单词

第二个表格是您的单词列表。通过添加交叉引用表来取消规范化,该表允许您快速定位哪些文件包含哪些单词


现在你可以把它扔掉了。

我想试试这样的东西。。。创建一个具有word/file-id的关联表。每条记录都有两个id加上一个完全由0和1组成的字符串

举个例子:

Text file X contents: "The quick brown fox jumps over the lazy dog"
                       0   1     2     3   4     5    6   7    8

Text file Y contents: "Now is the time for all good men"
                       0   1  2   3    4   5   6    7
您将获得:

WordId | FileId | Position
the    | X      | 100001
the    | Y      | 001
quick  | X      | 01
is     | Y      | 01
....
(请注意,该位置也可以存储为实际位掩码以节省空间,但我不确定在使用或更新值时这是否会有问题)

顺便说一句,这个技巧基于一种叫做“Rushmore索引”的东西

现在要查看文件“X”中“the”和“quick”之间的距离,必须读取两行,并计算“is”和“the”实例之间的零数。 请注意,您还可以添加额外的信息,如“文件中单词的出现次数”,以使实际距离匹配更容易:

WordId | FileId | Position |Occ
the    | X      | 100001   | 2
the    | Y      | 000001   | 1 
quick  | X      | 01       | 1
is     | Y      | 01       | 1
....

在这种情况下,您会立即知道“the”在文件X中出现两次,而“quick”只会出现一次。这可能有助于构建距离计数例程。

对于您正在做的事情来说,一个DB是多余的。您是否考虑过使用类似的或更轻的东西? 您可能应该在后台创建一些工作线程来更新索引
有很多线程更新它。这将减少争用…

假设您的纯文本文档只包含索引词(即没有标点符号之类的未索引部分,或者您满足于将标点符号包含在索引中),也许以下想法值得一试:

如您所见,没有单独的“文档”内容。“文档”和“索引”是一个整体,可以通过按适当顺序遍历文档单词并从单词中查找单词文本来动态重建文档

此模型有两个很好的特性:

  • 数据不会在文档和索引之间重复,从而节省空间
  • 同一个单词可以被许多文档共享——单词文本只存储一次,这节省了空间。这实际上是一种字典压缩
  • DOCUMENT_WORD是一个很好的候选词,因此同一文档中的所有单词都存储在物理上接近的位置,这将使文档重建过程中的I/O最小化
  • 通过一点连接,您可以在两个方向上进行查询:“获取给定位置上(或附近)的单词”或“获取给定单词的位置”

顺便说一句,如果您决定切换到Oracle,您可以使用领先的索引压缩和DOCUMENT\u WORD上的群集,以消除文档ID的重复并节省更多空间。您可以使用SQL Server来达到类似的效果。

注释搞乱了代码格式,因此:

我将上面的帖子标记为答案,因为这是我设计的解决方案的核心。我将位置和单词id存储在xml列中,唯一的单词被规范化为单独的查找表。搜索时,我执行类似于以下内容的XPath查询:

m.WordIndex.query('
    let $dummy := 0
    return
        <word_list>
        {
            for $w in /wi/w
                where $w/@wid=1
                return <word wid="1" pos="{data($w/p)}"/>
        }
        </word_list>
    ') as WordPosition
m.WordIndex.query('
设$dummy:=0
返回
{
价格为$w in/wi/w
其中$w/@wid=1
返回
}
“)作为单词位置

您真的希望仅以文件中的词序而不是(Unicode)来定位吗字符偏移量?偏移量可以让您轻松提取包含原始大小写和标点符号的短语。它有助于了解您计划对数据执行何种查询,以建议适当的设计。我基本上实现了pico lucene:)我将执行搜索查询,如:find me word“internet”在“探险家”的5个字之内,也许我遗漏了什么,但你的问题是。。。每个表的行太多?记录的字段太多?或者绝对值中的行太多?我不知道SQL Server Express的限制……可能在SQL Express(10 GB)中遇到数据库大小限制。-如果需要更多的存储,则需要考虑标准版。您有冲突的要求:您想要的是快速的(避免锁争用),并且占用尽可能少的空间。(您选择的数据库的限制)。如果您为锁定进行优化,您会创建太多的行,如果您为大小进行优化(我怀疑您在大小方面可能比bitarray做得更好),您会遇到锁争用…嗯,我的“文件”数量可以很容易地达到1000万左右。非规范化查找会将行数放大到无法管理的数字。事实上,SQL Server