我有一系列unigrams(单字),bigrams(两个单词)和trigrams(三个单词)我从一堆文件中提取出来。我的目标是静态分析报告以及我可以在这些文档上使用的搜索。
John Doe
Xeon 5668x
corporate tax rates
beach
tax plan
Porta San Giovanni
ngrams按日期和文档标记。因此,例如,我可以找到双字母组合之间的关系,以及它们的短语首次出现时以及文档之间的关系。我还可以搜索包含这些X个un / bi / trigram短语的文档。
所以我的问题是如何存储它们以优化这些搜索。
最简单的方法只是每个短语的一个简单的字符串列,然后每当我在文档中找到该单词/短语时,我就会向document_ngram表添加关系。
table document
{
id
text
date
}
table ngram
{
id
ngram varchar(200);
}
table document_ngram
{
id
ngram_id
document_id
date
}
然而,这意味着如果我想通过三字母搜索单个单词,我必须使用字符串搜索。例如,假设我想要所有包含“summer”字样的三元组。
因此,如果我将这些单词分开,以便ngram中存储的唯一内容是单个单词,则添加三列,以便所有1,2和& 3个字链可以放在document_ngram
内吗?
table document_ngram
{
id
word1_id NOT NULL
word2_id DEFAULT NULL
word3_id DEFAULT NULL
document_id
date
}
这是正确的方法吗?他们是更好的方式吗?我目前正在使用PostgreSQL和MySQL,但我相信这是一个通用的SQL问题。
答案 0 :(得分:11)
这就是我对数据进行建模的方法(请注意''被引用两次)您还可以为单个单词添加权重。
DROP SCHEMA ngram CASCADE;
CREATE SCHEMA ngram;
SET search_path='ngram';
CREATE table word
( word_id INTEGER PRIMARY KEY
, the_word varchar
, constraint word_the_word UNIQUE (the_word)
);
CREATE table ngram
( ngram_id INTEGER PRIMARY KEY
, n INTEGER NOT NULL -- arity
, weight REAL -- payload
);
CREATE TABLE ngram_word
( ngram_id INTEGER NOT NULL REFERENCES ngram(ngram_id)
, seq INTEGER NOT NULL
, word_id INTEGER NOT NULL REFERENCES word(word_id)
, PRIMARY KEY (ngram_id,seq)
);
INSERT INTO word(word_id,the_word) VALUES
(1, 'the') ,(2, 'man') ,(3, 'who') ,(4, 'sold') ,(5, 'world' );
INSERT INTO ngram(ngram_id, n, weight) VALUES
(101, 6, 1.0);
INSERT INTO ngram_word(ngram_id,seq,word_id) VALUES
( 101, 1, 1)
, ( 101, 2, 2)
, ( 101, 3, 3)
, ( 101, 4, 4)
, ( 101, 5, 1)
, ( 101, 6, 5)
;
SELECT w.*
FROM ngram_word nw
JOIN word w ON w.word_id = nw.word_id
WHERE ngram_id = 101
ORDER BY seq;
结果:
word_id | the_word
---------+----------
1 | the
2 | man
3 | who
4 | sold
1 | the
5 | world
(6 rows)
现在,假设您要为现有(6克)数据添加4克:
INSERT INTO word(word_id,the_word) VALUES
(6, 'is') ,(7, 'lost') ;
INSERT INTO ngram(ngram_id, n, weight) VALUES
(102, 4, 0.1);
INSERT INTO ngram_word(ngram_id,seq,word_id) VALUES
( 102, 1, 1)
, ( 102, 2, 2)
, ( 102, 3, 6)
, ( 102, 4, 7)
;
SELECT w.*
FROM ngram_word nw
JOIN word w ON w.word_id = nw.word_id
WHERE ngram_id = 102
ORDER BY seq;
其他结果:
INSERT 0 2
INSERT 0 1
INSERT 0 4
word_id | the_word
---------+----------
1 | the
2 | man
6 | is
7 | lost
(4 rows)
BTW:向此模型添加文档类型对象将向此模型添加两个附加表:一个用于文档,另一个用于文档* ngram。 (或在另一种方法中:对于文档*单词)递归模型也是可能的。
更新:上述模型需要一个额外的约束,需要实现触发器(或规则+附加表)。伪代码:
ngram_word.seq >0 AND ngram_word.seq <= (select ngram.n FROM ngram ng WHERE ng.ngram_id = ngram_word.ngram_id)
答案 1 :(得分:0)
一个想法是稍微修改原始表格布局。考虑ngram varchar(200)列只包含ngram的1个字,添加到word_no(1,2或3)列,并添加到分组列中,以便例如两个字的两个记录在一个二元组中是相关的(给他们相同的word_group)。 [在Oracle中,我从Sequence
中提取word_group数字 - 我认为PostGres会有类似的东西)
table document
{
id
text
date
}
table ngram
{
id
word_group
word_no
ngram varchar(200);
}
table document_ngram
{
id
ngram_id
document_id
date
}