文档字索引数据库结构?

时间:2012-03-15 14:49:42

标签: mysql database-design indexing

说我想要识别文档的几页(可能大约500页以上)中出现的所有单词。我已经完成了查找单词出现在哪个页面的工作。因此,例如,我想列出计算机一词出现的所有页面。

将这些数据存储为可通过Web服务快速搜索的最佳方法是什么?我的直觉就是做一些事情:

表格结构: varchar(30)WORD,blob PAGES

让PAGES字段为出现该单词的所有页面的逗号分隔列表,然后将其展开并在查询与WORD字段匹配时列出所有页面。我想知道是否有更有效的方法来实现这一目标?我可能会使用MySQL和PHP / Zend,因为这是我最熟悉的。但如果你有更好的想法,我肯定愿意听到它们。

该表可能会变得非常长,因为我需要为文档中的每个唯一单词添加一行。也许我会设置一个不超过3或4个字符的限制,但我仍然可以想象超过10-20k字。如果我按字母顺序排列行列表,我可以以某种方式在我的数据库服务器上更容易吗? (即苹果,苹果,分支是按升序排列的吗?)MySQL可以处理这个吗?还有别的东西可以更好地处理吗?

最后,是否有更好的结构模式,以后可能会让我收集/提供有趣的数据? (即,向用户提供经常出现在附近的相关单词等)。

3 个答案:

答案 0 :(得分:4)

您必须规范化您的数据库。

首先是一个存储页面的表

table pages (
  id unsigned integer auto_increment primary key,
  page blob,
  other_interesting_data_about_a_page )

然后是一个用于保存单词的表

table wc (
  id unsigned integer auto_increment primary key
  word varchar(20) unique key,
  count unsigned integer default 1,
  other_interesting_data_about_a_word.... )

然后是一个表格,用于将单词链接到页面

table word_page (
  word_id unsigned integer,
  page_id unsiged integer,
  pos_in_page unsigned integer,  /*position*/
  primary key pk (word_id, page_id, pos_in_page) )

现在您可以查询页面中的单词数量:

SELECT COUNT(*) 
FROM word_page 
WHERE page_id = 123

或在页面中重复单词'the'的次数。

SELECT COUNT(*)
FROM word_page wp 
INNER JOIN wc ON (wp.word_id = wc.id)
WHERE wp.page_id = 123 AND wc.word = 'the'

警告语

  

让PAGES字段成为所有页面的逗号分隔列表.....

永远不要在数据库中使用CSV,这是你可以使用的最糟糕的反模式,如果你堕落,它会一遍又一遍地咬你。
如果您感觉到需要,请将自己踢到头部,直到冲动消失为止,然后再使用一个或两个单独的桌子。

答案 1 :(得分:3)

与标准化相反,这对于这个特定问题通常是一种良好的做法,但是空间效率很低,你可能想要坚持你的结构,但用一个位向量替换你的blob中的页面列表(仍然在blob列),每个位代表一个页面。优点是,对于500页,即使该单词出现在所有页面中(500/8 = 62.5),一个单词的该向量的最大大小也将是63字节。

在位域内,每个页面对应一个位号:如果位号N为ON,则表示该单词出现在第N页,否则它不出现在第N页。 这是DBIx SQL text indexing implementation基本使用的结构 位从右到左编号,可以删除非重要的0。

例如,如果第3,4和12页中出现“计算机”一词,则该值为: 二进制100000001100(十进制表示= 2060)。

如果仅在第400页出现,则数字1后跟399 0's。如果它出现在每个页面上,则该值将是数字1的500倍。

我一直在postgresql数据库中使用该表示(加分区)来全文索引邮件内容,并且我发现它的扩展性非常好,这与仅对非常小的表现良好的天真规范化实现相反数据集。

答案 2 :(得分:1)

为了便于维护和索引,我将设置一个带有计算的primarey键的映射表: id BIGINT AUTO_INCREMENT, 字VARCHAR(30), 页面INT, ... 并为单词和页面构建索引。 这样,您就更灵活,不需要爆炸列表甚至可以访问某些统计信息(哪些页面使用更多独特的单词等)。

MySQL(以及所有其他关系数据库引擎)使用树结构构建自己的内部索引,无需预先对数据进行排序。

这个表很容易被MySQL处理。可能还有更快的其他数据库引擎,但这是一个不错的开始。

当然你可以添加更多的表,即word,other_word,distance,这一切都取决于你的规范以及解析器的可能性。

如果你有时间浏览一下,看看searchengines如何,例如solr / lucene正在处理这些事情