我有N-grams的大型数据库(原始未压缩文本大约2 TB)。 4克的示例行看起来像:
cat in the cradle 2
cat in the hat 187
cat in the window 32
即。 4个字符串文本,带有一个(可能很大的)整数(w1,w2,w3,w4,c)
。我已设法将数据放在数据库中,并在[w1,w2,w3]
上建立索引。查找第一个单词与给定查询匹配的内容,最后一个单词是wild:
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]
构建索引,因此任何答案都应该尝试适应这些约束。
答案 0 :(得分:3)
您可以考虑将单词拆分为单独的表格,例如
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 :(得分: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时它才有效。 (注意像''的空字符串不是空的)
无论如何,我建议尝试使用EXPLAIN命令检查它。
答案 2 :(得分:1)
如果您无法预测访问模式,或者您必须容纳多种任意访问模式,则单列索引可能是更好的选择。测试将告诉;尝试在开发计算机上测试一部分数据。
如果在四列{w1,w2,w3,w4}的组合上构建索引,那么从WHERE子句中省略列w1的任何查询都可能不使用索引。 “帽子里的猫”,“帽子里的男人”和“帽子里的人”这两个值在复合指数中都会被广泛分开。
您的dbms,无论哪一个,都会为您提供一些方法来查看查询优化器正在执行的操作。
答案 3 :(得分:0)
在(w2,w3)上创建复合索引。使用带有WHERE
子句的查询,该子句在索引顺序中比较w2
和w3
,然后使用其他非索引比较。
SELECT * FROM db WHERE (w2="in" AND w3="the" AND w1="cat")
SELECT * FROM db WHERE (w2="in" AND w3="the" AND w4="hat")