web-dev-qa-db-ja.com

mongoDBプレフィックスワイルドカード:fulltext-search($ text)search-stringで部分を検索

$text-Indexと次のような要素を持つmongodbがあります。

{
   foo: "my super cool item"
}
{
   foo: "your not so cool item"
}

で検索する場合

mycoll.find({ $text: { $search: "super"} })

最初のアイテムを取得します(正しい)。

しかし、「uper」で検索して最初のアイテムを取得したいのですが、試してみると:

mycoll.find({ $text: { $search: "uper"} })

結果が得られません。

私の質問:$ textを使用して、検索文字列の一部で結果を見つける方法がある場合は? (例:mysql'%uper%'など)

注意:正規表現のみの検索は要求しません-$ text-search内で正規表現検索を要求します!

45
mdunisch

$text演算子で実行することはできません。

テキストインデックスは、文字列値または文字列配列に含まれる用語で作成され、検索はそれらのidexeに基づいています。

語句をグループ化することはできますが、それらに参加することはできません。

$text演算子リファレンス および テキストインデックスの説明 をお読みください。

45
francadaval

2番目の例でしようとしているのは、コレクションmycollのフィールドfooのプレフィックスワイルドカード検索です。これはtextsearch機能が設計されたものではなく、$text演算子で実行することはできません。 この動作 は、インデックス付きフィールドの特定のトークンに対するワイルドカードプレフィックス検索を含みません。ただし、他の人が提案したように、代わりに正規表現検索を実行することもできます。これが私のチュートリアルです。

>db.mycoll.find()
{ "_id" : ObjectId("53add9364dfbffa0471c6e8e"), "foo" : "my super cool item" }
{ "_id" : ObjectId("53add9674dfbffa0471c6e8f"), "foo" : "your not so cool item" }
> db.mycoll.find({ $text: { $search: "super"} })
{ "_id" : ObjectId("53add9364dfbffa0471c6e8e"), "foo" : "my super cool item" }
> db.mycoll.count({ $text: { $search: "uper"} })
0

$text演算子は、単一の単語の検索、1つ以上の単語の検索、またはフレーズの検索をサポートします。希望する種類の検索はサポートされていません

正規表現ソリューション:

> db.mycoll.find({foo:/uper/})
{ "_id" : ObjectId("53add9364dfbffa0471c6e8e"), "foo" : "my super cool item" }
> 

最後の質問への答え:mongoDBでmysqlスタイル%super%を実行するには、おそらく実行する必要があります。

db.mycoll.find( { foo : /.*super.*/ } );
14
user508434

/uper/で動作するはずです。

詳細については、 http://docs.mongodb.org/manual/reference/operator/query/regex/ を参照してください。

編集:

コメントのリクエストごと:

解決策は、実際にOP requestedを提供することを必ずしも意味するものではありませんでしたが、彼が問題を解決するために必要なものを提供するものでした。

$regex検索はテキストインデックスでは機能しないため、インデックスフィールドに対する単純な正規表現検索では、要求されたmeansを使用していなくても、期待されるresultが返されます。

実際、これは非常に簡単です。

db.collection.insert( {foo: "my super cool item"} )
db.collection.insert( {foo: "your not so cool item"})
db.collection.ensureIndex({ foo: 1 })
db.collection.find({'foo': /uper/})

期待される結果が得られます。

{ "_id" : ObjectId("557f3ba4c1664dadf9fcfe47"), "foo" : "my super cool item" }

追加の説明は、インデックスが効率的に使用されたことを示しています。

{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "test.collection",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "foo" : /uper/
        },
        "winningPlan" : {
            "stage" : "FETCH",
            "inputStage" : {
                "stage" : "IXSCAN",
                "filter" : {
                    "foo" : /uper/
                },
                "keyPattern" : {
                    "foo" : 1
                },
                "indexName" : "foo_1",
                "isMultiKey" : false,
                "direction" : "forward",
                "indexBounds" : {
                    "foo" : [
                        "[\"\", {})",
                        "[/uper/, /uper/]"
                    ]
                }
            }
        },
        "rejectedPlans" : [ ]
    },
    "serverInfo" : {
        // skipped
    },
    "ok" : 1
}

簡単に言うと、いいえ:$textインデックスを再利用することはできませんが、クエリを効率的に実行できます。 MongoDB検索を使用したオートコンプリート機能の実装 で記述されているように、おそらくmap/reduceアプローチを使用して、インデックスから冗長性と不要なストップワードを排除することで、より効率的になる可能性がありますもうリアルタイム。

9

私はjasenkohソリューションをコメントするのに十分な評判はありませんが、これは明らかにこの状況に対処するための最良の方法です。

OPの状況では、私は:

db.mycoll.createIndex( { foo: "text" } )
db.mycoll.createIndex( { foo: 1 } )
db.mycoll.find({$or: [{$text: {$search: 'uper'}}, {foo: {$regex: 'uper'}}]})

パフォーマンスを向上させるには(ただし、結果が少し異なります)、最後の行を次のように置き換えます。

db.mycoll.find({$or: [{$text: {$search: 'uper'}}, {foo: {$regex: '^uper'}}]})

Francadavalが言ったように、テキストインデックスは用語で検索していますが、regextext-indexあなたは良いはずです。

mycoll.find({$or: [ 
  { 
    $text: {
      $search: "super"
    }
  },
  {
    'column-name': {
      $regex: 'uper',
      $options: 'i'
  }
]})

また、テキストインデックス以外の列に通常のインデックスが適用されていることを確認してください。

2
jasenkoh

正規表現を使用すると、「スーパーアイテム」ではなく「スーパークール」の検索を実行できます。検索用語に対して$ textと$ regexを使用して要求または要求の両方を実行できます。

テキストインデックスと通常のインデックスの両方が機能するようにインデックスを作成してください。

1

あなたが達成できた可能性は

db.mycoll.find( {foo: { $regex :  /uper/i  } })

ここで、「i」はオプションで、大文字と小文字を区別しない検索を示します

0
mohit_IBS