【问题标题】:Lookup strategy for database of N-gramsN-gram数据库的查找策略
【发布时间】:2011-11-23 17:03:31
【问题描述】:

我有一个N-grams 的大型数据库(原始未压缩文本约为 2 TB)。 4-gram 的示例行如下所示:

cat in the cradle 2
cat in the hat 187
cat in the window 32

即4 个字符串文本,带有一个(可能很大)整数 (w1,w2,w3,w4,c)。我已经设法将数据放入带有[w1,w2,w3] 索引的数据库中。查找第一个单词与给定查询匹配并且最后一个单词是百搭的:

SELECT * FROM db WHERE (w1="cat" AND w2="in" AND w3="the")

很快。我对那个查询和第一个词是狂野的查询都感兴趣:

SELECT * FROM db WHERE (w2="in" AND w3="the" AND w4="hat")

无论我如何设计索引或数据库,查询都很慢或数据库大小膨胀到极端。此外,在我的计算机上构建索引需要几天时间,因此实验速度很慢。我正在寻找有关如何管理此类查询的建议。我认为我没有足够的硬盘空间来为[w1,w2,w3][w2,w3,w4] 建立索引,所以任何答案都应该尽量适应这些限制。

【问题讨论】:

    标签: database database-design language-agnostic


    【解决方案1】:

    您可以考虑将单词拆分到单独的表格中,例如

    CREATE TABLE word
      ( id INT PRIMARY KEY
      , text VARCHAR(32) NOT NULL UNIQUE
      )
    

    每个唯一单词的字符仅存储一个副本,可能会节省磁盘空间(仅“可能”取决于平均单词长度)。更重要的是,现在只有一个基于字符串的索引可用于所有单词,无论它们在 N-gram 中的位置如何。 N-gram 将通过它们的主键标识符而不是它们的文本来引用单词:

    CREATE TABLE ngram
       ( id INT PRIMARY KEY
       , w1Id INT FOREIGN KEY REFERENCES word(id)
       , w2Id INT FOREIGN KEY REFERENCES word(id)
       , w3Id INT FOREIGN KEY REFERENCES word(id)
       , w4Id INT FOREIGN KEY REFERENCES word(id)
       , n INT NOT NULL
       )
    

    所有外键索引都是基于整数的,而不是基于字符串的。

    查询可以这样表达:

    SELECT w1.text, w2.text, w3.text, w4.text, ng.n
    FROM ngram AS ng
    INNER JOIN word AS w1 ON w1.id = ng.w1Id
    INNER JOIN word AS w2 ON w2.id = ng.w2Id AND w2.text = 'in'
    INNER JOIN word AS w3 ON w3.id = ng.w3Id AND w2.text = 'the'
    INNER JOIN word AS w4 ON w4.id = ng.w4Id AND w2.text = 'hat'
    

    【讨论】:

    • +1。有趣的是,我们几乎同时用类似的方法解决了类似的问题,不是吗 (stackoverflow.com/questions/8247005/…)?
    • @Leonid 我不得不仔细查看是否是同一张海报。如果是同一个响应者,也许海报是双重的? ;)
    【解决方案2】:

    来自 MySQL 手册:

    如果表有一个多列索引,优化器可以使用索引的任何最左边的前缀来查找行。例如,如果您在 (col1, col2, col3) 上有一个三列索引,则您在 (col1)、(col1, col2) 和 (col1, col2, col3) 上有索引搜索功能。

    如果列不构成索引的最左前缀,则 MySQL 不能使用索引。假设您有此处显示的 SELECT 语句:

    因此,您可以尝试使用所有四列(w1、w2、w3、w4)创建索引,然后将第二个查询更改为如下所示:

    SELECT * FROM db WHERE (w1 IS NOT NULL AND w2="in" AND w3="the" AND w4="hat")
    

    这应该使用索引,但当然它只有在你没有 w1 设置为 NULL 的 n-gram 时才有效。 (注意像 '' 这样的空字符串不是 Null)

    无论如何我建议尝试使用 EXPLAIN 命令来检查它。

    【讨论】:

      【解决方案3】:

      如果您无法预测访问模式,或者您必须适应多种任意访问模式,那么单列索引可能是更好的选择。测试会告诉你;尝试在开发计算机上测试数据的子集。

      如果您在四列 {w1, w2, w3, w4} 的组合上构建索引,则任何在 WHERE 子句中省略列 w1 的查询将可能不使用该索引。 “cat in the hat”、“man in the hat”和“where in the hat”这些值在综合索引中都将被广泛分开。

      无论是哪一个,您的 dbms 都会为您提供一些方法来查看查询优化器在做什么。

      【讨论】:

        【解决方案4】:

        在 (w2, w3) 上创建复合索引。使用带有WHERE 子句的查询,按索引顺序比较w2w3,然后使用其他非索引比较。

        SELECT * FROM db WHERE (w2="in" AND w3="the" AND w1="cat") 
        SELECT * FROM db WHERE (w2="in" AND w3="the" AND w4="hat") 
        

        【讨论】:

          猜你喜欢
          • 2011-01-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-01-31
          • 1970-01-01
          • 1970-01-01
          • 2013-09-11
          相关资源
          最近更新 更多