วิธีเก็บ Google ngrams ในฐานข้อมูลได้ดีที่สุด


9

ฉันดาวน์โหลด google onegrams เมื่อหลายวันก่อนและมันมีข้อมูลจำนวนมากแล้ว ฉันใส่ 10 แพ็คเกจแรกลงใน mysql และตอนนี้ฉันมีฐานข้อมูลบันทึก 47 ล้านชุด

ฉันสงสัยว่าควรเก็บ Google ngrams ไว้ในฐานข้อมูลอย่างไรดีที่สุด ฉันหมายความว่าถ้าคุณไม่ได้ใช้งาน onegrams แต่เช่น twograms หรือสามกรัมจำนวนเงินจะมากขึ้น ฉันสามารถบันทึก 500 ล้านเร็กคอร์ดในฐานข้อมูลเดียวและทำงานกับมันหรือฉันควรจะแบ่งมันออกเป็นตารางต่าง ๆ หรือไม่?

หลังจากนั้นควรมีการบันทึกจำนวนเท่าใดและควรแยกกันอย่างไรดีที่สุด (เนื่องจาก twograms นั้นมี 100 ไฟล์และน่าจะมีประมาณ 5 พันล้านรายการ) แนะนำให้ใช้ MySQL การแบ่งพาร์ติชันตามแนวนอนหรือสร้างการแบ่งพาร์ติชันของตัวเอง (เช่นผ่านตัวอักษรตัวแรกของ word => twograms_a)

คำตอบ:


4

มีการเปลี่ยนแปลงมากมายที่ฉันจะต้องทำกับคำตอบแรกของฉันฉันเริ่มต้น !!!

USE test
DROP TABLE IF EXISTS ngram_key;
DROP TABLE IF EXISTS ngram_rec;
DROP TABLE IF EXISTS ngram_blk;
CREATE TABLE ngram_key
(
    NGRAM_ID UNSIGNED BIGINT NOT NULL AUTO_INCREMENT,
    NGRAM VARCHAR(64) NOT NULL,
    PRIMARY KEY (NGRAM),
    KEY (NGRAM_ID)
) ENGINE=MyISAM ROW_FORMAT=FIXED PARTITION BY KEY(NGRAM) PARTITIONS 256;
CREATE TABLE ngram_rec
(
    NGRAM_ID UNSIGNED BIGINT NOT NULL,
    YR SMALLINT NOT NULL,
    MC SMALLINT NOT NULL,
    PC SMALLINT NOT NULL,
    VC SMALLINT NOT NULL,
    PRIMARY KEY (NGRAM_ID,YR)
) ENGINE=MyISAM ROW_FORMAT=FIXED;
CREATE TABLE ngram_blk
(
    NGRAM VARCHAR(64) NOT NULL,
    YR SMALLINT NOT NULL,
    MC SMALLINT NOT NULL,
    PC SMALLINT NOT NULL,
    VC SMALLINT NOT NULL
) ENGINE=BLACKHOLE;
DELIMITER $$
CREATE TRIGGER populate_ngram AFTER INSERT ON ngram_blk FOR EACH ROW
BEGIN
    DECLARE NEW_ID BIGINT;

    INSERT IGNORE INTO ngram_key (NGRAM) VALUES (NEW.NGRAM);
    SELECT NGRAM_ID INTO NEW_ID FROM ngram_key WHERE NGRAM=NEW.NGRAM;
    INSERT IGNORE INTO ngram_rec VALUES (NEW_ID,NEW.YR,NEW.MC,NEW.PC,NEW.VC);
END; $$
DELIMITER ;
INSERT INTO ngram_blk 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);
UPDATE ngram_rec SET yr=yr+1,mc=mc+30,pc=pc+30,vc=vc+30;
INSERT INTO ngram_blk 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);
UPDATE ngram_rec SET yr=yr+1,mc=mc+30,pc=pc+30;
INSERT INTO ngram_blk 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);
UPDATE ngram_rec SET yr=yr+1,mc=mc+30;
SELECT * FROM ngram_key;
SELECT * FROM ngram_rec;
SELECT A.ngram NGram,B.yr Year,B.mc Matches,B.pc Pages,B.vc Volumes FROM 
ngram_key A,ngram_rec B
WHERE A.ngram='rolando angel edwards'
AND A.ngram_id=B.ngram_id;

ตารางมีขนาดเล็กกว่ามากสำหรับข้อมูลปี แต่มีปุ่มที่ใหญ่กว่าเพื่อรักษา ngram ดั้งเดิม ฉันยังเพิ่มปริมาณข้อมูลทดสอบ คุณสามารถตัดและวางสิ่งนี้ลงใน MySQL ได้โดยตรง

ข้อแม้

เพียงเอา ROW_FORMAT ออกแล้วมันจะกลายเป็น dymanic และบีบอัดตาราง ngram_key ให้เล็กลงมาก


ตัวชี้วัด DiskSpace

nrgram_rec มี 17 ไบต์ต่อแถว
8 ไบต์สำหรับ ngram_id (ค่าสูงสุดที่ไม่ได้ลงนาม 18446744073709551615 [2 ^ 64 - 1])
8 ไบต์สำหรับ 4 smallints (2 ไบต์ต่อหน้า)
1 ไบต์ลบธง MyISAM ภายใน 1

รายการดัชนีสำหรับ ngram_rec = 10 ไบต์ (8 (ngram_id) + 2 (ปี))

47 ล้านแถว X 17 ไบต์ต่อแถว = 0799 ล้านไบต์ = 761.98577 MB
47 ล้านแถว X 12 ไบต์ต่อแถว = 0564 ล้านไบต์ = 537.85231 MB
47 ล้านแถว X 29 ไบต์ต่อแถว = 1363 ล้านไบต์ = 1.269393 GB

5 พันล้านแถว X 17 ไบต์ต่อแถว = 085 พันล้านไบต์ = 079.1624 GB
5 พันล้านแถว X 12 ไบต์ต่อแถว = 060 ล้านไบต์ = 055.8793 GB
5 ล้านแถว X 29 ไบต์ต่อแถว = 145 ล้านไบต์ = 135.0417 GB


ngram_key มี 73 ไบต์ 64 ไบต์สำหรับ ngram (ROW_FORMAT = แก้ไขชุด varchar ให้เป็นถ่าน) 8 ไบต์สำหรับ ngram_id 1 ไบต์แฟล็กการลบภายใน MyISAM

2 รายการดัชนีสำหรับ ngram_key = 64 ไบต์ + 8 ไบต์ = 72 ไบต์

47 ล้านแถว X 073 ไบต์ต่อแถว = 3431 ล้านไบต์ = 3.1954 GB
47 ล้านแถว X 072 ไบต์ต่อแถว = 3384 ล้านไบต์ = 3.1515 GB
47 ล้านแถว X 145 ไบต์ต่อแถว = 6815 ล้านไบต์ = 6.3469 GB

5 พันล้านแถว X 073 ไบต์ต่อแถว = 365 ล้านไบต์ = 339.9327 GB
5 พันล้านแถว X 072 ไบต์ต่อแถว = 360 ล้านไบต์ = 335.2761 GB
5 พันล้านแถว X 145 ไบต์ต่อแถว = 725 พันล้านไบต์ = 675.2088 GB


ขอบคุณสำหรับคำตอบที่ดีสองข้อ ฉันอยากรู้ว่าอะไรคือสาเหตุของการใช้วิธีเรียกทริกเกอร์ blackhole + สำหรับการเติมข้อมูลในตาราง
Dolan Antenucci

Blackhole ยอมรับ ngram แบบดั้งเดิม ทริกเกอร์สร้างกลไก INSERT IGNORE ที่สะอาดเพื่อแยก ngram จากค่า auto_increment
RolandoMySQLDBA

3

นี่คือคำแนะนำที่น่ารัก

แปลง ngrams ทั้งหมดเป็นคีย์ MD5 32 ตัว

ตารางนี้จะจัดเก็บ npg ทุกขนาด (สูงสุด 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;

เหตุผลที่ฉันเลือก 256 พาร์ติชั่นนั้นเกิดจากความจริงที่ว่าฟังก์ชั่น MD5 ส่งกลับ 16 ตัวอักษรที่แตกต่างกัน (ตัวเลขฐานสิบหกทั้งหมด) สองไบต์แรกคือ 16 X 16, 256

นี่คือผลลัพธ์ใน MySQL 5.5.11 บน Windows 7 Desktop ของฉัน

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>

โปรดสังเกตว่าฉันโหลด 1 กรัม, 2 กรัมและ 3 กรัมลงในตารางเดียวกัน แต่คุณไม่มีเงื่อนงำใดที่ MD5 เป็นของ ngram ใด ดังนั้น ngrams ทั้งหมดสามารถติดตั้งเพิ่มเติมในตารางนี้ เพียงจำไว้ว่าให้แทรกลงในตาราง ngram_blackhole และส่วนที่เหลือจะทำเพื่อคุณ

คุณต้องค้นหาตาราง ngram_node โดยใช้ MD5 () ของ ngram ไม่ว่า ngram ใด

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)

หากคุณต้องการแยก 1 -GG, 2-G และ 3-G ลงในที่เก็บแยกต่างหากเพียงแค่สร้างตารางอื่นตาราง Blackhole อีกอันและทริกเกอร์อื่นบนตาราง Blackhole เพื่อแทรกลงในตารางอื่น

นอกจากนี้หาก ngrams ของคุณมีความยาวมากกว่า 255 (ถ้าคุณทำขนาด 7 กรัมหรือ 8 กรัม) เพียงเพิ่มขนาด VARCHAR ของคอลัมน์ NGRAM ในตาราง ngram_blackhole

ให้มันลอง !!!

UPDATE

ในคำถามมันระบุว่า 47 ล้านแถวถูกโหลดลงใน mysql สำหรับรูปแบบตารางที่แนะนำของฉันโปรดทราบดังต่อไปนี้:

ngram_node คือ 41 ไบต์ต่อแถว: 32 สำหรับ NGRAM_KEY
8 สำหรับตัวเลข (2 สำหรับแต่ละ SMALLINT)
1 สำหรับการลบ MyISAM ภายใน

รายการดัชนีคีย์หลักแต่ละรายการจะมีขนาด 34 ไบต์
32 สำหรับ NGRAM_KEY
2 สำหรับ NGRAM_YEAR

47 ล้านแถว X 41 ไบต์ต่อแถว = 1.927 พันล้านไบต์, ประมาณ 1.79466 GB
47 ล้านแถว X 34 ไบต์ต่อรายการดัชนี = 1.598 พันล้านไบต์ประมาณ 1.48825 GB
ปริมาณการใช้ตาราง MyISAM ควรจะอยู่ที่ประมาณ 3.28291 GB

คำถามดังกล่าวยังกล่าวถึงการโหลด 5 พันล้านแถว

5 พันล้านแถว X 41 ไบต์ต่อแถว = 205 พันล้านไบต์, ประมาณ 190.9211 GB
5 พันล้านแถว X 34 ไบต์ต่อรายการดัชนี = 170 ล้านไบต์, ประมาณ 158.3248 GB
ปริมาณการใช้ตาราง MyISAM ควรมีขนาดรวมประมาณ 349.2459 GB

โปรดสังเกตว่าอัตราการเติบโตของพื้นที่ที่ใช้ในตาราง MyISAM เป็นเส้นตรงเนื่องจากคีย์หลักขนาดคงที่ ตอนนี้คุณสามารถทำการวางแผนพื้นที่ดิสก์ได้ตามนี้


1
ฉันคิดถึงคำตอบของฉันและฉันมีคำแนะนำอื่นในใจเพื่อให้มีการใช้พื้นที่ดิสก์น้อยลง ฉันจะพูดเรื่องนี้ในวันจันทร์ !!! ขอให้มีความสุขในวันหยุดสุดสัปดาห์
RolandoMySQLDBA
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.