Подтвердить что ты не робот

MongoDB prefix wildcard: fulltext-search ($ text) найти часть с поисковой строкой

У меня есть mongodb с $text-Index и элементами вроде этого:

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

Если я выполняю поиск с помощью

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

я получаю первый элемент (правильный).

Но я также хочу искать с помощью "uper", чтобы получить элемент fist, но если я попробую:

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

Я не получаю никаких результатов.

Мой вопрос: Если есть способ использовать $text, чтобы найти его результаты с частью строки поиска? (например, как '%uper%' в mysql)

Внимание: я не запрашиваю только поиск по регулярному выражению - я запрашиваю регулярный поиск в текстовом поиске $

4b9b3361

Ответ 1

Невозможно сделать это с помощью оператора $text.

Текстовые индексы создаются с помощью терминов, включенных в строковое значение или в массив строк, и поиск основан на этих идексах.

Вы можете группировать термины только на основе pharse, но не принимать их.

Прочтите $text ссылку оператора и описание текстовых индексов.

Ответ 2

То, что вы пытаетесь сделать в своем втором примере, - это поиск подстановочных подстановок в вашей коллекции mycoll в поле foo. Это не то, для чего предназначена функция textearch, и это невозможно сделать с помощью оператора $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 поддерживает поиск одного слова, поиск одного или нескольких слов или поиск фразы. Тип поиска, который вы хотите, не поддерживается

Решение регулярного выражения:

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

Ответ на ваш последний вопрос: сделать mysql style %super% в mongoDB, который вам, скорее всего, придется сделать:

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

Ответ 3

Он должен работать с /uper/.

Подробнее см. http://docs.mongodb.org/manual/reference/operator/query/regex/.

Edit:

В соответствии с запросом в комментариях:

Решение не обязательно предназначалось для того, чтобы фактически дать то, что запросил ОП, но что ему нужно для решения проблемы.

Так как поиск $regex не работает с текстовыми индексами, простой поиск регулярных выражений по индексированному полю должен давать ожидаемый результат, но не использовать запрошенные средства.

На самом деле это довольно легко сделать:

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, исключающий избыточность и ненужные слова остановки из индексов, за счет того, что он больше не в режиме реального времени.

Ответ 4

Как сказал francadaval, текстовый индекс ищет термины, но если вы объедините regex и text-index, вы должны быть хорошими.

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

Кроме того, убедитесь, что у вас есть нормальный индекс, применяемый к столбцу, отличному от текстового индекса

Ответ 5

У меня недостаточно репутации, чтобы комментировать решение 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'}}]})