Mysql 文档词索引数据库结构?

Mysql 文档词索引数据库结构?,mysql,database-design,indexing,Mysql,Database Design,Indexing,假设我希望识别文档中几页中出现的所有单词(可能超过500页)。我已经完成了查找单词出现在哪一页的工作。例如,我想列出计算机这个词出现的所有页面 存储这些数据以便通过web服务快速搜索的最佳方式是什么?我的直觉是做一些事情,比如: 表结构: varchar(30)字,blob页 让PAGES字段是一个逗号分隔的列表,包含单词出现的所有页面,然后在查询匹配单词字段时将其分解并列出所有页面。我想知道是否有更有效的方法来实现这一点?我可能会使用MySQL和PHP/Zend,因为这是我最熟悉的。但如果你有

假设我希望识别文档中几页中出现的所有单词(可能超过500页)。我已经完成了查找单词出现在哪一页的工作。例如,我想列出计算机这个词出现的所有页面

存储这些数据以便通过web服务快速搜索的最佳方式是什么?我的直觉是做一些事情,比如:

表结构: varchar(30)字,blob页

让PAGES字段是一个逗号分隔的列表,包含单词出现的所有页面,然后在查询匹配单词字段时将其分解并列出所有页面。我想知道是否有更有效的方法来实现这一点?我可能会使用MySQL和PHP/Zend,因为这是我最熟悉的。但如果你有更好的想法,我绝对愿意听

该表可能会变得非常长,因为我需要为文档中的每个唯一单词指定一行。也许我设定了一个不少于3或4个字符的限制,但我仍然可以想象超过10-20k个单词。如果我按行列表的字母顺序排列,我能在数据库服务器上更方便吗?(苹果、苹果、树枝按升序排列)MySQL能处理吗?还有别的办法处理得更好吗


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

您必须规范化数据库

首先是存储页面的表

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,它是你能使用的最糟糕的反模式,如果你爱上它,它会一次又一次地咬你。

如果你觉得有必要,踢自己的头直到冲动消失,然后使用一个或两个单独的表来代替。

为了便于维护和索引,我会设置一个带有计算primarey键的映射表: id BIGINT自动增量, 单词VARCHAR(30), 第INT页, ... 并为word和page建立索引。 这样,您就更灵活了,不需要分解列表,甚至不需要访问一些统计数据(哪些页面使用了更多独特的单词等)

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

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

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


如果你有时间浏览一下,看看搜索引擎(例如solr/lucene)是如何处理这些事情的,而不是规范化,规范化通常是很好的做法,但对于这个特定问题来说空间效率很低,您可能希望坚持您的结构,但将blob中的页面列表替换为位向量(仍在blob列中),每个位表示一个页面。优点是,对于500页,一个字的向量的最大大小为63字节,即使该字出现在所有页中(500/8=62.5)

在位字段内,每一页对应一个位号:如果位号N为ON,则表示该单词出现在第N页,否则不会出现在第N页。 这是基本上由用户使用的结构 位从右向左编号,可以删除非有效0

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

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


我一直在postgresql数据库中使用这种表示(加上分区)对邮件内容进行全文索引,我发现它的可扩展性非常好,这与只在非常小的数据集上运行良好的朴素的规范化实现相反。

决不会考虑这样的事情,谢谢!我认为Johan的回答虽然成本更高,但它将使我能够对存储的数据做更多有趣的事情。@Emeka(也是),好主意David,但是在遇到速度/空间问题之前,不要临时去规范化。我想知道你是如何处理在一页上出现不止一次的单词的(但我现在太深入浅出了)。谢谢你关于Solr/Lucene的提示。可能会朝这个方向走!我永远不会在数据库中使用CSV:)谢谢你的提示!