web-dev-qa-db-ja.com

MongoDBの全文検索および部分的テキスト検索

環境:

  • MongoSを使用したMongoDB(3.2.0)

コレクション:

  • ユーザー

テキストインデックスの作成:

  BasicDBObject keys = new BasicDBObject();
  keys.put("name","text");

  BasicDBObject options = new BasicDBObject();
  options.put("name", "userTextSearch");
  options.put("unique", Boolean.FALSE);
  options.put("background", Boolean.TRUE);

  userCollection.createIndex(keys, options); // using MongoTemplate

資料:

  • {「名前」:「LEONEL」}

クエリ:

  • db.users.find( { "$text" : { "$search" : "LEONEL" } } ) => FOUND
  • db.users.find( { "$text" : { "$search" : "leonel" } } ) => FOUND(検索caseSensitiveはfalse)
  • db.users.find( { "$text" : { "$search" : "LEONÉL" } } ) => FOUND(diacriticSensitiveでの検索はfalse)
  • db.users.find( { "$text" : { "$search" : "LEONE" } } ) => FOUND(部分検索)
  • db.users.find( { "$text" : { "$search" : "LEO" } } ) => NOT FOUND(部分検索)
  • db.users.find( { "$text" : { "$search" : "L" } } ) => NOT FOUND(部分検索)

クエリとして「LEO」または「L」を使用して0個の結果が得られる理由はありますか?

テキストインデックス検索を使用した正規表現は許可されません。

db.getCollection('users')
     .find( { "$text" : { "$search" : "/LEO/i", 
                          "$caseSensitive": false, 
                          "$diacriticSensitive": false }} )
     .count() // 0 results

db.getCollection('users')
     .find( { "$text" : { "$search" : "LEO", 
                          "$caseSensitive": false, 
                          "$diacriticSensitive": false }} )
.count() // 0 results

Mongoドキュメント:

26
Leonel

MongoDB 3.4の場合、 テキスト検索 機能は、ストップワードとステミングの言語固有のルールを使用して、テキストコンテンツの大文字と小文字を区別しない検索をサポートするように設計されています。 サポートされている言語 のステミングルールは、一般的な動詞と名詞を一般的に処理するが適切な名詞を認識しない標準アルゴリズムに基づいています。

部分一致またはあいまい一致の明示的なサポートはありませんが、同様の結果をもたらす用語はそのように機能しているように見える場合があります。たとえば、「taste」、「tastes」、およびtastefulはすべて「tast」になります。 Snowball Stemming Demo ページを試して、より多くの単語とステミングアルゴリズムを試してください。

一致する結果はすべて同じ単語「LEONEL」のバリエーションであり、大文字と小文字の区別のみが異なります。選択した言語のルールによって「LEONEL」をより短いものに絞り込めない限り、これらが一致する唯一のバリエーションです。

効率的な部分一致を行いたい場合は、別のアプローチをとる必要があります。役に立つアイデアについては、以下を参照してください。

MongoDB課題トラッカーで監視/投票できる関連する改善要求があります: SERVER-15090:部分的な単語一致をサポートするためのテキストインデックスの改善

45
Stennie

Mongoは現在、デフォルトで部分検索をサポートしていないため...

簡単な静的メソッドを作成しました。

import mongoose from 'mongoose'

const PostSchema = new mongoose.Schema({
    title: { type: String, default: '', trim: true },
    body: { type: String, default: '', trim: true },
});

PostSchema.index({ title: "text", body: "text",},
    { weights: { title: 5, body: 3, } })

PostSchema.statics = {
    searchPartial: function(q, callback) {
        return this.find({
            $or: [
                { "title": new RegExp(q, "gi") },
                { "body": new RegExp(q, "gi") },
            ]
        }, callback);
    },

    searchFull: function (q, callback) {
        return this.find({
            $text: { $search: q, $caseSensitive: false }
        }, callback)
    },

    search: function(q, callback) {
        this.searchFull(q, (err, data) => {
            if (err) return callback(err, data);
            if (!err && data.length) return callback(err, data);
            if (!err && data.length === 0) return this.searchPartial(q, callback);
        });
    },
}

export default mongoose.models.Post || mongoose.model('Post', PostSchema)

使い方:

import Post from '../models/post'

Post.search('Firs', function(err, data) {
   console.log(data);
})
7
Ricardo Canelas

インデックスを作成せずに、単純に使用できます:

db.users.find({ name: /<full_or_partial_text>/i})(大文字と小文字を区別しない)

0
nurealam siddiq