几天前我下载了google onegrams,它已经是海量的数据了。我将 10 个包中的第一个插入到 mysql 中,现在我有一个 4700 万条记录数据库。
我想知道如何最好地将 Google ngrams 存储在数据库中。我的意思是,如果您使用的不是一克,而是例如两克或三克,则数量会大得多。我可以在一个数据库中存储 5 亿条记录并使用它,还是应该将其拆分到不同的表中?
应该在多少条记录之后拆分它以及如何最好地拆分它(考虑到 twograms 有 100 个文件,因此可能有大约 50 亿条记录)?是否建议使用 MySQL 水平分区或构建自己的分区(例如,通过 word => twograms_a 的第一个字符)。
这是一个非常疯狂的建议
将所有 ngram 转换为 32 字符 MD5 密钥
该表将保存任意大小的所有 ngram(最多 255 个字符)、1-gram、2-gram 等。
use test
DROP TABLE ngram_node;
DROP TABLE ngram_blackhole;
CREATE TABLE ngram_node
(
NGRAM_KEY CHAR(32) NOT NULL,
NGRAM_YEAR SMALLINT NOT NULL,
M_COUNT SMALLINT NOT NULL,
P_COUNT SMALLINT NOT NULL,
V_COUNT SMALLINT NOT NULL,
PRIMARY KEY (NGRAM_KEY,NGRAM_YEAR)
) ENGINE=MyISAM
PARTITION BY KEY(NGRAM_KEY)
PARTITIONS 256;
CREATE TABLE ngram_blackhole
(
NGRAM VARCHAR(255) NOT NULL,
NGRAM_YEAR SMALLINT NOT NULL,
M_COUNT SMALLINT NOT NULL,
P_COUNT SMALLINT NOT NULL,
V_COUNT SMALLINT NOT NULL
) ENGINE=BLACKHOLE;
DELIMITER $$
CREATE TRIGGER populate_ngram AFTER INSERT ON ngram_blackhole FOR EACH ROW
BEGIN
INSERT INTO ngram_node VALUES (MD5(NEW.NGRAM),NEW.NGRAM_YEAR,NEW.M_COUNT,NEW.P_COUNT,NEW.V_COUNT);
END; $$
DELIMITER ;
INSERT INTO ngram_blackhole VALUES
('rolando',1965,31,29,85),
('pamela',1971,33,21,86),
('dominique',1996,30,18,87),
('diamond',1998,13,28,88),
('rolando edwards',1965,31,29,85),
('pamela edwards',1971,33,21,86),
('dominique edwards',1996,30,18,87),
('diamond edwards',1998,13,28,88),
('rolando angel edwards',1965,31,29,85),
('pamela claricia edwards',1971,33,21,86),
('dominique sharlisee edwards',1996,30,18,87),
('diamond ashley edwards',1998,13,28,88);
SELECT * FROM ngram_node;
Run Code Online (Sandbox Code Playgroud)
我选择 256 个分区的原因是 MD5 函数返回 16 个不同的字符(均为十六进制数字)。前两个字节是 16 X 16, 256。
这是我的 Windows 7 桌面上 MySQL 5.5.11 的结果
mysql> use test
Database changed
mysql> DROP TABLE ngram_node;
Query OK, 0 rows affected (0.22 sec)
mysql> DROP TABLE ngram_blackhole;
Query OK, 0 rows affected (0.11 sec)
mysql> CREATE TABLE ngram_node
-> (
-> NGRAM_KEY CHAR(32) NOT NULL,
-> NGRAM_YEAR SMALLINT NOT NULL,
-> M_COUNT SMALLINT NOT NULL,
-> P_COUNT SMALLINT NOT NULL,
-> V_COUNT SMALLINT NOT NULL,
-> PRIMARY KEY (NGRAM_KEY,NGRAM_YEAR)
-> ) ENGINE=MyISAM
-> PARTITION BY KEY(NGRAM_KEY)
-> PARTITIONS 256;
Query OK, 0 rows affected (0.36 sec)
mysql> CREATE TABLE ngram_blackhole
-> (
-> NGRAM VARCHAR(255) NOT NULL,
-> NGRAM_YEAR SMALLINT NOT NULL,
-> M_COUNT SMALLINT NOT NULL,
-> P_COUNT SMALLINT NOT NULL,
-> V_COUNT SMALLINT NOT NULL
-> ) ENGINE=BLACKHOLE;
Query OK, 0 rows affected (0.11 sec)
mysql> DELIMITER $$
mysql> CREATE TRIGGER populate_ngram AFTER INSERT ON ngram_blackhole FOR EACH ROW
-> BEGIN
-> INSERT INTO ngram_node VALUES (MD5(NEW.NGRAM),NEW.NGRAM_YEAR,NEW.M_COUNT,NEW.P_COUNT,NEW.V_COUNT);
-> END; $$
Query OK, 0 rows affected (0.05 sec)
mysql> DELIMITER ;
mysql> INSERT INTO ngram_blackhole VALUES
-> ('rolando',1965,31,29,85),
-> ('pamela',1971,33,21,86),
-> ('dominique',1996,30,18,87),
-> ('diamond',1998,13,28,88),
-> ('rolando edwards',1965,31,29,85),
-> ('pamela edwards',1971,33,21,86),
-> ('dominique edwards',1996,30,18,87),
-> ('diamond edwards',1998,13,28,88),
-> ('rolando angel edwards',1965,31,29,85),
-> ('pamela claricia edwards',1971,33,21,86),
-> ('dominique sharlisee edwards',1996,30,18,87),
-> ('diamond ashley edwards',1998,13,28,88);
Query OK, 12 rows affected (0.18 sec)
Records: 12 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM ngram_node;
+----------------------------------+------------+---------+---------+---------+
| NGRAM_KEY | NGRAM_YEAR | M_COUNT | P_COUNT | V_COUNT |
+----------------------------------+------------+---------+---------+---------+
| 2ca237192aaac3b3a20ce0649351b395 | 1996 | 30 | 18 | 87 |
| 6f7fd3368170c562604f62fb4e92056d | 1965 | 31 | 29 | 85 |
| fb201333fef377917be714dabd3776d9 | 1971 | 33 | 21 | 86 |
| 4f79e21800ed6e30be4d1cb597f910c6 | 1971 | 33 | 21 | 86 |
| 9068e0de9f3fd674d4fa7cbc626e5888 | 1998 | 13 | 28 | 88 |
| 8a18abe90f2612827dc3a215fd1905d3 | 1965 | 31 | 29 | 85 |
| be60b431a46fcc7bf5ee4f7712993e3b | 1996 | 30 | 18 | 87 |
| c8adc38aa00759488b1d759aa8f91725 | 1996 | 30 | 18 | 87 |
| e80d4ab77eb18a4ca350157fd487d7e2 | 1965 | 31 | 29 | 85 |
| 669ffc150d1f875819183addfc842cab | 1971 | 33 | 21 | 86 |
| b685323e9de65080f733b53b2305da6e | 1998 | 13 | 28 | 88 |
| 75c6f03161d020201000414cd1501f9f | 1998 | 13 | 28 | 88 |
+----------------------------------+------------+---------+---------+---------+
12 rows in set (0.00 sec)
mysql>
Run Code Online (Sandbox Code Playgroud)
请注意,我将 1-grams、2-grams 和 3-grams 加载到同一个表中,但您不知道哪个 MD5 属于哪个 ngram。因此,所有 ngram 都可以改装到这张表中。只需记住插入到 ngram_blackhole 表中,剩下的就为您完成了。
无论是哪个 ngram,都必须使用 ngram 的 MD5() 查询 ngram_node 表。
mysql> select * from ngram_node where ngram_key=MD5('rolando edwards');
+----------------------------------+------------+---------+---------+---------+
| NGRAM_KEY | NGRAM_YEAR | M_COUNT | P_COUNT | V_COUNT |
+----------------------------------+------------+---------+---------+---------+
| 6f7fd3368170c562604f62fb4e92056d | 1965 | 31 | 29 | 85 |
+----------------------------------+------------+---------+---------+---------+
1 row in set (0.05 sec)
Run Code Online (Sandbox Code Playgroud)
如果您希望将 1-gram、2-gram 和 3-gram 分离到单独的存储库中,只需创建另一个表、另一个黑洞表,并在黑洞表上创建另一个触发器以插入到另一个表中。
另外,如果您的 ngram 长度超过 255(如果您正在执行 7-gram 或 8-gram),只需增加 ngram_blackhole 表中 NGRAM 列的 VARCHAR 大小即可。
试一试 !!!
更新
在问题中,据说有4700万行被加载到mysql中。对于我建议的表格布局,请注意以下几点:
ngram_node 每行 41 个字节: 32 表示 NGRAM_KEY
8 表示数字(每个 SMALLINT 2 个)
1 表示内部 MyISAM DELETED 标志
每个主键索引条目将为 34 个字节
32 对于 NGRAM_KEY
2 对于 NGRAM_YEAR
4700 万行 X 每行 41 字节 = 19.27 亿字节,约 1.79466 GB。
4700 万行 X 每个索引条目 34 字节 = 15.98 亿字节,约 1.48825 GB。
MyISAM 表消耗总计约为 3.28291 GB。
该问题还提到加载 50 亿行。
50 亿行 X 每行 41 字节 = 2050 亿字节,约 190.9211 GB。
50 亿行 X 每个索引条目 34 字节 = 1700 亿字节,大约 158.3248 GB。
MyISAM 表消耗总计约为 349.2459 GB。
请注意,由于主键大小恒定,MyISAM 表中使用的空间的增长率是线性的。您现在可以基于此对磁盘空间进行一些规划。