2013-07-30 17 views
11

MongoDBを使って自然言語辞書を実装しようとしています。私は字句の集まりを持っています。それぞれの字句はサブ文書として数多くあります。現在、私はいくつかの4000の語彙素のコレクションを持っており、これらのそれぞれは、いくつかの1000年wordforms(上記わずか2とは反対に)の平均リストにありMongoDBの正規表現文字列検索を高速化

{ 
    "_id" : ObjectId("51ecff7ee36f2317c9000000"), 
    "pos" : "N", 
    "lemma" : "skrun", 
    "gloss" : "screw", 
    "wordforms" : [ 
     { 
      "number" : "sg", 
      "surface_form" : "skrun", 
      "phonetic" : "ˈskruːn", 
      "gender" : "m" 
     }, 
     { 
      "number" : "pl", 
      "surface_form" : "skrejjen", 
      "phonetic" : "'skrɛjjɛn", 
      "pattern" : "CCCVCCVC" 
     } 
    ], 
    "source" : "Mayer2013" 
} 

:これは、単一の語彙素がどのように見えるかです。これは、私が感情的にコレクションに4,000,000のユニークな単語形式を持っていることを意味し、合理的な時間内にそれを検索する必要があります。

通常のクエリは次のようになります。

db.lexemes.find({"wordforms.surface_form":"skrejjen"}) 

私はwordforms.surface_formのインデックスを持っており、この検索は非常に高速です。 しかし、検索でワイルドカードを使用したい場合は、パフォーマンスは重大です。たとえば:

db.lexemes.find({"wordforms.surface_form":/skrej/}) 

(この時点で私は待っていました)。前述のようにin this questionでは、インデックスの正規表現検索が悪いことが知られています。私は、正規表現で^アンカーを追加するとhelps a lotを検索することがわかっていますが、検索機能も厳しく制限されています。私がその犠牲を払うことを喜んでしているとしても、私は応答時間が正規表現に依存して変わることに気付いています。クエリ

db.lexemes.find({"wordforms.surface_form":/^s/}) 

完了までに35秒かかります。

これまでのところ、hintを使用してインデックスをオフにしたときの最良の結果が得られました。 この場合、物事はかなり良くなるようです。このクエリ:

db.lexemes.find({"wordforms.surface_form":/skrej/}).hint('_id_') 

完了までに3秒かかります。

私の質問は、これらの検索時間を改善するために何かできますか?彼らはまだ、彼らはまだ少し遅いですし、私はすでにパフォーマンスを得るためにMySQLに移行することを検討しています。しかし、私は本当にMongoの柔軟性を保ち、RDBMSのすべての退屈な正規化を避けたいと思います。助言がありますか?私はDBエンジンに関係なく、この量のテキストデータを使って、いくらか遅くなると思いますか?

私はMongoの新しいtext search機能について知っていますが、この(トークン化とステミング)の利点は私の場合は関係ありません(私の言語はサポートされていません)。テキスト検索が実際により速い場合は正規表現を使用するよりも明らかではありません。

答えて

7

Derickが提案したように、私はデータベース内のデータをリファームして、 "語彙"の下のサブ文書ではなく "wordforms"をコレクションとしてリファクタリングしました。 結果は実際より優れていました! いくつかの速度比較があります。 hintを使用する最後の例では、意図的に古いスキーマで実際に高速だったsurface_formのインデックスをバイパスしています。私にとって

旧スキーマoriginal questionを参照)

Query                Avg. Time 
db.lexemes.find({"wordforms.surface_form":"skrun"})    0s 
db.lexemes.find({"wordforms.surface_form":/^skr/})     1.0s 
db.lexemes.find({"wordforms.surface_form":/skru/})     > 3mins ! 
db.lexemes.find({"wordforms.surface_form":/skru/}).hint('_id_') 2.8s 

新しいスキーマDerick's answerを参照)

Query                Avg. Time 
db.wordforms.find({"surface_form":"skrun"})      0s 
db.wordforms.find({"surface_form":/^skr/})       0.001s 
db.wordforms.find({"surface_form":/skru/})       1.4s 
db.wordforms.find({"surface_form":/skru/}).hint('_id_')   3.0s 

これは、リファクタリングスキーマが速く検索するだろうことはかなり良い証拠であります冗長データ(または余分な結合が必要)の価値があります。

9

考えられるすべてのバリアントを配列要素として保存することも可能ですが、可能かどうかはわかりません。

{ 
     "number" : "pl", 
     "surface_form" : "skrejjen", 
     "surface_forms: [ "skrej", "skre" ], 
     "phonetic" : "'skrɛjjɛn", 
     "pattern" : "CCCVCCVC" 
    } 

私はおそらく、各単語に1000語のフォームを保存しないように勧めますが、これを回してより小さな文書を作成してください。

{ 
    "word": { 
     "pos" : "N", 
     "lemma" : "skrun", 
     "gloss" : "screw", 
    }, 
    "form" : { 
     "number" : "sg", 
     "surface_form" : "skrun", 
     "phonetic" : "ˈskruːn", 
     "gender" : "m" 
    }, 
    "source" : "Mayer2013" 
} 

{ 
    "word": { 
     "pos" : "N", 
     "lemma" : "skrun", 
     "gloss" : "screw", 
    }, 
    "form" : { 
     "number" : "pl", 
     "surface_form" : "skrejjen", 
     "phonetic" : "'skrɛjjɛn", 
     "pattern" : "CCCVCCVC" 
    }, 
    "source" : "Mayer2013" 
} 

私もMySQLはあろうことを疑う:(検索条件はもちろんのフルスキャンを必要としない限り)あなたの文書である小さい方が、より少ないMongoDBは、各検索のためにメモリに読み込まなければならないだろうMongoDBのように完全なテーブルスキャンを行わなければならないので、ここでは無作為な単語形式の検索でより良い結果が得られます。クエリーキャッシュがあるのを助けることができるのは唯一のことですが、それはあなたのアプリケーションの検索UI/APIで非常に簡単に構築できるものです。

+0

お寄せいただきありがとうございます!これはもちろん、冗長な情報をたくさん導入し、全体的なコレクションを大きくしますが、検索応答時間が長くなると、それを考慮する可能性があります。私はこれが事実であるかどうかを確認するためにいくつかのテストを行い、ここにアップデートを掲載します。 –