Qiitaにもポストしたんですがこちらにも記載。まだブログとQiitaとGistの使い分けが上手くできてない。みんなどうやって使い分けてるのだろうか?
機能特徴
- 複数の文字列フィールドでテキストインデックス作成できる
- 1つのコレクションに対して、1つの索引を作成できる
- テキストインデックスは、アプリケーションがデータベースからドキュメントを
- insert,update,deleteしたらリアルタイムで更新される。
- 対応言語は以下のとおり
- danish
- dutch
- english
- finnish
- french
- german
- hungarian
- italian
- norwegian
- portuguese
- romanian
- russian
- spanish
- swedish
- turkish
デメリット
- テキストインデックスは肥大化する。(各ドキュメントの各インデックス内に、ユニークな次のステムワードを持ってる)
- インデックス作成する時間は通常のインデックスを作成するよりも時間がかかる。
- データ挿入スループットは低下する。(MongoDBは各ドキュメントの各インデックス内に、ユニークな次のステムワードを追加しなければならないため)
- テキスト検索はmongodの性能に影響があるだろう。特にNOT検索やフレーズマッチは効果的にインデックスを有効活用できない。
現時点の制約
- テキストインデックスはドキュメント内の単語のち情報を格納してはならない。コレクション全体がRAMに収まると、効果的な検索ができる。
- MongoDBは否定語やフレーズを軸にしない
- インデックスは大文字/小文字を区別しない
- コレクションは一度に一つのテキストインデックスしか持てない。
- 結果はBSON Document Size(16MB)に収める必要がある。(後述するproject,filterなどを使用する)
コマンド
全文検索を使うには
db.adminCommand( { setParameter: 1, textSearchEnabled: true } )
もしくは、
mongod --setParameter textSearchEnabled=true
Index作成
- content, subject インデックス対象
- 別コレクションも対象にできる。
- field名 : 1 もしくは-1と書くと昇順/降順の作成も付与できる。
- name 索引名
- weights 重み
また、ワイルドカード指定もできる。更に昇順/降順の索引も付与できる。
// ワイルドカード指定時 db.contents.ensureIndex({ "$**":"text"}, {name:"ContentsIndex"});
db.contents.ensureIndex( {content: "text", subject: "text", <field>:1 or (-1)}, {name:"ContentsIndex", weights:{content:10, subject:5}} ) db.contents.getIndexes() [ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "blogs.contents", "name" : "_id_" }, { "v" : 1, "key" : { "_fts" : "text", "_ftsx" : 1 }, "ns" : "blogs.contents", "name" : "ContentsIndex", "weights" : { "content" : 10, "subject" : 5 }, "default_language" : "english", "language_override" : "language", "textIndexVersion" : 1 } ]
検索方法
db.<コレクション名>.runCommand("text", { search: <string>, filter: <document>, project: <document>, limit: <number>, language: <string> } );
search
検索対象の文字列.半角スペースで区切るとorで検索を行う。Not検索はワードの前に"-"をつける。(例:A not B -> A -B)
また、A B Cという単語を検索する場合には "\"A B C \""とダブルクオーテーションを使用する。
filter
指定フィールドに指定文字列が含まれているデータを検索対象にする.
MongoDBで有効なドキュメントを使用できる。
filterの条件に一致するデータを出力する。
例えば fliter : { createAt: { $gt : new Date()}} という指定もできる。
先頭にasc or descとしてindexをつけた場合はfilter設定は必須かつ、equalの条件にする必要がある。
例えば、
db.contents.ensureIndex({ blogId:1, content: "text", subject: "text"})
というindexを作成した場合は、以下のようなコマンドしか受け付けない。
db.contents.runCommand("text" , { search: "indonesia", filter:{blogId : 100}}); db.contents.runCommand("text" , { search: "indonesia", filter:{blogId : {$gt:100}}}); { "ok" : 0, "errmsg" : "BadValue need have an equality filter on: blogId" }
project
戻りフィールドを限定する.
limit
検索結果件数
language
トークンなどに関わってくる検索言語を指定.デフォルトは英語
今のところ日本語は対応していない。
出力内容
パラメータ名 | 内容 | |
---|---|---|
language | 全文検索を行った言語 | |
results | 検索結果やスコアを格納した配列 | |
results.score | 検索結果のスコア | |
results.obj | 検索結果のオブジェクト | |
stats | ステータスを格納したオブジェクト | |
stats.nscanned | 検索したindex数 | |
stats.nscannedObjects | 検索したドキュメント数(filterを設定するとカウントアップされる) | |
stats.n | resultsの要素数. BSON Document Sizeを越えた場合、resultsの要素数より少なくなる場合がある | |
stats.nfound | ドキュメントが一致している総数を返却する。BSON Document Sizeを越えた場合はstats.nより大きくなる場合がある | |
stats.timeMicro | 検索にかかった時間(マイクロ秒) | |
ok | 1 が返却される |
db.contents.runCommand("text", { search: "america"}); { "queryDebugString" : "america||||||", "language" : "english", "results" : [ { "score" : 7.5, "obj" : { "_id" : ObjectId("5151abf80e5ebfcf71b9f9f9"), "contentsId" : 10000, "blogId" : 100, "subject" : "アメリカ訪問", "content" : "Let's go America", "createAt" : 1364306936770 } }, { "score" : 7.5, "obj" : { "_id" : ObjectId("5151abf80e5ebfcf71b9f9fa"), "contentsId" : 11000, "blogId" : 100, "subject" : "アメリカ訪問", "content" : "遊びにいった i have been to Amarica", "createAt" : 1364306936775 } }, { "score" : 7.5, "obj" : { "_id" : ObjectId("5151abf80e5ebfcf71b9f9fb"), "contentsId" : 12000, "blogId" : 100, "subject" : "America訪問", "content" : "Amaricaへ遊びにいった i have been to Amarica", "createAt" : 1364306936779 } } ], "stats" : { "nscanned" : 3, "nscannedObjects" : 0, "n" : 3, "nfound" : 3, "timeMicros" : 96 }, "ok" : 1 }
contentsIdとcontentのみ出力を絞る
db.contents.runCommand("text", { search: "america", project: {contentsId:1, content:1}}); { "queryDebugString" : "america||||||", "language" : "english", "results" : [ { "score" : 11.25, "obj" : { "_id" : ObjectId("5151abf80e5ebfcf71b9f9fc"), "contentsId" : 20000, "content" : "i have been to america. アメリカ言ってみた" } } ], "stats" : { "nscanned" : 1, "nscannedObjects" : 0, "n" : 1, "nfound" : 1, "timeMicros" : 76 }, "ok" : 1 }