Mysql 在RDBMS中存储uni/bi/Trigram和ngrams的正确方法?

Mysql 在RDBMS中存储uni/bi/Trigram和ngrams的正确方法?,mysql,sql,postgresql,rdbms,n-gram,Mysql,Sql,Postgresql,Rdbms,N Gram,我有一个单字、双字和三字的列表,我从一堆文档中提取了这些单字。我的目标是一个静态分析报告,也是一个我可以在这些文档上使用的搜索 John Doe Xeon 5668x corporate tax rates beach tax plan Porta San Giovanni ngrams按日期和文件进行标记。例如,我可以找到大字组之间的关系,以及它们的短语首次出现的时间,以及文档之间的关系。我还可以搜索包含X个un/bi/trigram短语的文档 所以我的问题是如何存储它们来优化这些搜索 最简

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

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
}
然而,这意味着,如果我想通过三角形搜索单个单词,我必须使用字符串搜索。例如,假设我想要所有有“夏天”字样的三叉树

因此,如果我将单词拆分,使存储在ngram中的唯一内容是一个单词,然后添加三列,以便所有1、2和3个单词链都可以放入
文档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 0 2
INSERT 0 1
INSERT 0 4
 word_id | the_word 
---------+----------
       1 | the
       2 | man
       6 | is
       7 | lost
(4 rows)
顺便说一句:向该模型添加文档类型对象将向该模型添加两个附加表:一个用于文档,另一个用于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)

ngram_word.seq>0和ngram_word.seq一个想法是稍微修改一下原始的表布局。考虑NGRAM VARCHAR(200)列仅包含NGRAM的1个字,添加WordNoNO(1, 2,或3)列,并添加到分组列中,以便例如,在二元RAM中的两个字的两个记录相关(给它们相同的WorddGROUP)。[在甲骨文中,我会从
序列中提取单词\u组号
——我想PostGres也会有类似的东西)


“document_ngram”的最后一个版本包含一个重复组。您需要一个额外的表来避免这种情况。(第二个版本将重复组放入字符串中,这更糟)@wildplasser,“重复组”是什么意思?1NF:word1\u id、word2\u id、word3\u id本质上是一个数组。使用非关系数据库可能会有更好的结果-您考虑过这个选项吗?本教程可能很相关,它使用了
MySQL
R
:不错。这是存储单词的正确方法,因此它们不会重复,也很容易查询。单词是实体。ngram是实体。文档是实体。其余的是实体之间的关系。我正在尝试解决这个问题。ngram表上的权重列是什么?既然我需要将ngram链接到文档,我会添加一个文档ngram表,其中包括
日期、ngram单词id、文档id
,并修改
ngram单词
表t吗o还有主键吗?另外,
word\u id
&
ngram\u id
在现实生活中是一个序列,对吗?权重列是未使用的有效载荷,但我用它来显示如何存储ngram的属性(在大多数情况下:权重或频率)。文档表只是层次结构中的另一层:文档指的是单词和/或ngram。文档还可以包含一些摘要信息(如有效性、重要性等),是的,单词id和ngram id可以是序列。(但它们也可以指由程序/数据库外的另一个进程强加的编号)
 ngram_word.seq >0 AND ngram_word.seq <= (select ngram.n FROM ngram ng WHERE ng.ngram_id = ngram_word.ngram_id)
table document
{
    id
    text
    date
}

table ngram
{
    id
    word_group
    word_no
    ngram varchar(200);
}

table document_ngram
{
    id
    ngram_id
    document_id
    date
}