我有一个单字、双字和三字的列表,我从一堆文档中提取出来。我的目标是一个静态分析报告,同时也是一个我可以在这些文档上使用的搜索。

John Doe
Xeon 5668x
corporate tax rates
beach
tax plan
Porta San Giovanni

ngram按日期和文档进行标记。例如,我可以找到大词和它们的短语首次出现的时间之间的关系以及文档之间的关系。我还可以搜索包含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
}

但是,这意味着如果我想通过三元组搜索单个单词,我必须使用字符串搜索。比如说,我想要所有三联图中都有“夏天”这个词。
所以,如果我把单词分开,这样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问题。

最佳答案

这就是我如何为你的数据建模(注意‘the’被引用了两次)你也可以为单个单词添加权重。

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)

顺便说一句:在这个模型中添加一个document type对象将向这个模型添加两个额外的表:一个用于文档,另一个用于document*ngram。(或者在另一种方法中:对于document*word)递归模型也是可能的。
更新:上面的模型将需要一个额外的约束,它将需要触发器(或一个规则+一个额外的表)来实现。伪码:
 ngram_word.seq >0 AND ngram_word.seq <= (select ngram.n FROM ngram ng WHERE ng.ngram_id = ngram_word.ngram_id)

10-08 12:59