2

大量のドキュメントから取り出したユニグラム (1 つの単語)、バイグラム (2 つの単語)、およびトライグラム (3 つの単語) のリストがあります。私の目標は、レポートを静的に分析することと、これらのドキュメントで使用できる検索を行うことです。

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 つの単語だけになるように単語を分割し、1、2、および 3 つの単語チェーンがすべて収まるように 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 の質問だと思います。

4

2 に答える 2

11

これがデータのモデル化方法です(「the」は2回参照されていることに注意してください)。単一の単語に重みを追加することもできます。

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)

ところで:このモデルにドキュメントタイプのオブジェクトを追加すると、このモデルに2つのテーブルが追加されます。1つはドキュメント用、もう1つは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)
于 2012-06-09T18:31:10.190 に答える
0

1つのアイデアは、元のテーブルレイアウトを少し変更することです。ngram varchar(200)列にngramの1単語のみが含まれ、word_no(1、2、または3)列を追加し、グループ化列を追加するとします。たとえば、2つの単語の2つのレコードが含まれます。バイグラムでは関連しています(同じword_groupを指定してください)。[Oracleでは、word_group番号をSequence-から取得します-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
}
于 2012-06-09T18:32:09.950 に答える