0

次の設計上の問題があります。

サイズが約10KBのプレーンテキストファイルが100万個あるとします。私の目標は、すべての単語のインデックスを保存する方法を考案して、各単語を特定のテキストファイルとそのファイル内の単語の場所にリンクできるようにすることです。

例:

Text file X contents: "The quick brown fox jumps over the lazy dog"
                       0   1     2     3   4     5    6   7    8

Text file Y contents: "Now is the time for all good men"
                       0   1  2   3    4   5   6    7

おおまかに以下を保存したい:

the   => {X,0}, {X,6}, {Y,2}
quick => {X,1}
is    => {Y,1}
.... and so on

明らかに、私は実際にはプレーンテキストファイルのインデックスを作成していません。私のインデクサーは、「ファイル」、「単語」、「位置」という用語への入力を抽出するマルチスレッドC#アプリケーションです。行数が20億を超えると簡単に増えるため、一般的なルックアップテーブルセットを作成できません。

私の最初のアイデアは、ペア{message、position}を単語自体でプライマリキーが設定されたテキストブロブに格納することでした。ただし、このソリューションでは、すべてのスレッドが{message、position}の新しいペアで「the」の行を更新しようとすると、大きな競合が発生するのではないかと心配しています。

私は自分の環境であるSQLServerExpress 2012にロックされているので、現在の環境で作業してみましょう。データベース自体で何でもできます。実際、私のアプリは通常のワークフローの一部としてデータベースを作成するため、必要に応じてCLRストアドプロシージャをデプロイできます。

アイデア?

4

5 に答える 5

1

何かを捨てるだけで、ファイルごとに1行のテーブルを作成します。列を使用しxmlて、ファイルの出現語を格納します。

2番目の表は単語リストです。どのファイルにどの単語が含まれているかをすばやく見つけることができる相互参照テーブルを追加して、非正規化します。

今、あなたはそれを捨てることができます。

于 2012-07-11T03:39:24.733 に答える
1

私はこのようなことを試みます...word/file-idで関連付けテーブルを作成します。すべてのレコードには、2つのIDに加えて、完全に0と1で構成される文字列が含まれます。

だからあなたの例を考えると:

Text file X contents: "The quick brown fox jumps over the lazy dog"
                       0   1     2     3   4     5    6   7    8

Text file Y contents: "Now is the time for all good men"
                       0   1  2   3    4   5   6    7

あなたが得るでしょう:

WordId | FileId | Position
the    | X      | 100001
the    | Y      | 001
quick  | X      | 01
is     | Y      | 01
....

(スペースを節約するために位置を実際のビットマスクとして保存することもできますが、値を使用または更新するときにこれが問題にならないかどうかはわかりません)

このトリックは、「RushmoreIndexing」と呼ばれるものに基づいています。

ここで、ファイル「X」の「the」と「quick」の間の距離を確認するには、両方の行を読み取り、「is」のインスタンスと「the」のインスタンスの間のゼロの数を数える必要があります。「ファイル内の単語の出現回数」などの情報を追加して、実際の距離の一致を容易にすることもできます。

WordId | FileId | Position |Occ
the    | X      | 100001   | 2
the    | Y      | 000001   | 1 
quick  | X      | 01       | 1
is     | Y      | 01       | 1
....

この場合、「the」はファイルXに2回表示されますが、「quick」は1回だけ表示されることがすぐにわかります。これは、距離カウントルーチンを構成するのに便利な場合があります。

于 2012-07-11T07:02:54.970 に答える
0

DBは、あなたがしていることに対してやり過ぎです。NoSQLのようなものやさらに軽いものを使用することを検討しましたか?また、多くのスレッドでインデックスを更新するのではなく、バックグラウンドでインデックスを更新するワーカースレッドを作成する必要があります。それは競合を減らすでしょう...

于 2012-07-11T22:02:47.090 に答える
0

プレーンテキストドキュメントが索引付けされた単語のみで構成されていると仮定すると(つまり、句読点などの索引付けされていない部分がないか、句読点を索引に含めることに満足している)、おそらく次のアイデアは試してみる価値があります。

ここに画像の説明を入力してください

ご覧のとおり、個別の「ドキュメント」コンテンツはありません。「ドキュメント」と「インデックス」は同じものであり、DOCUMENT_WORDを適切な順序でトラバースし、WORDからWORD_TEXTを検索することで、ドキュメントをその場で再構築できます。

このモデルには、いくつかの優れたプロパティがあります。

  • ドキュメントとインデックス間でデータが複製されないため、スペースを節約できます。
  • 同じ単語を多くのドキュメントで共有できます。単語のテキストは1回だけ保存されるため、スペースを節約できます。これは実際には辞書圧縮の形式です。
  • DOCUMENT_WORDはクラスタリングに適した候補であるため、同じドキュメントのすべての単語が物理的に近くに保存され、ドキュメントの再構築中のI/Oを最小限に抑える必要があります。
  • 少し結合するだけで、「指定された位置に(または近くに)単語を取得する」または「指定された単語の位置を取得する」のいずれかの方向でクエリを実行できます。

ところで、Oracleに切り替えることにした場合は、DOCUMENT_WORDでのクラスタリングと組み合わせて最先端のインデックス圧縮を使用して、DOCUMENT_IDの繰り返しを排除し、さらに多くのスペースを節約できます。SQLServerのページ圧縮を使用して同様の効果を得ることができる場合があります。

于 2012-07-12T17:39:22.590 に答える
0

コメントはコードのフォーマットを台無しにするので、ここに行きます:

これが私が考案したソリューションの中核であるため、上記の投稿を回答としてマークしています。位置と単語IDをxml列に格納します。一意の単語は、個別のルックアップテーブルに正規化されます。検索するときは、次のようなXPathクエリを実行します。

m.WordIndex.query('
    let $dummy := 0
    return
        <word_list>
        {
            for $w in /wi/w
                where $w/@wid=1
                return <word wid="1" pos="{data($w/p)}"/>
        }
        </word_list>
    ') as WordPosition
于 2012-07-19T18:39:54.993 に答える