0

Итак, я прочитал this, но все же немного запутался в том, как это сделать.Использование весов для поиска в mongoose

Моя модель содержит различные поля, которые являются строками, числами и булевыми значениями.

$ текст кажется, что он может принимать только строки.

Что делать, если я хотел бы сделать поиск, как:

model.find({petsAllowed:true, rooms:4, house:"townhouse"}).sort() 

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

Я знаю, что mongoose поддерживает это, поэтому я не хочу полагаться на плагин.

Вот результат я хочу:

[ 
Document 1 (most closely matched with the input): 
    {petsAllowed:true, rooms:4, house:"townhouse"}, 
Document 2: {petsAllowed:false, rooms:4, house:"townhouse"}, 
Document 3: {petsAllowed:true, rooms:5, house:"townhouse"}, 
Document 4: {petsAllowed:false, rooms:3, house:"townhouse"} 
] 
+0

Ну '$ text' - довольно подходящее имя для оператора текстового поиска, так как это то, что он делает. Действительно, что бы вы ожидали от «ближайшего» к логическим или числовым значениям? Они в значительной степени абсолютны. Если вы хотите что-то «нечеткое» от них, то используйте «дальность» операторов, таких как '$ gte' и' $ lte', и, возможно, опустить логическое значение, если только вы на самом деле ** только ** хотите вернуть результаты, соответствующие этим условиям. –

+0

Ну, заданные поля ввода, они должны быть объединены вместе, так что если у документа есть полевые животные, то, как и правда, оно должно быть включено в результаты. Затем все эти результаты должны быть отсортированы на основе того, какие совпадения результатов закрываются с введенным. – user1883614

+0

Итак, вы хотите в качестве примера: '" petsAllowed ": true' быть в верхней части результатов, но также включать значения' false' под ними. Похоже, что вы спрашиваете? Более или менее добавляйте к оценке веса для каждого из этих условий, которые являются точным совпадением, а затем сначала сортируйте результаты с наивысшим баллом. Так что положите свою мысленную шапку. Как вы вычисляете значения в запросе MongoDB, а затем используете рассчитанный результат для сортировки? Ответ есть, но это не так эффективно. –

ответ

1

Для того, чтобы «вес» ответ, то основной принцип заключается в том, вы должны определить, какие части результата являются более важными для поиска вы выполняете и по существу предоставить соответствующий балл по порядку важности результата в соответствии с вашими правилами.

Это действительно вещь MongoDB, а не внешняя кодировка, поскольку вам нужно анализировать результаты на сервере, особенно если вы рассматриваете что-то вроде «подкачки» взвешенных результатов, когда их много. Для этого на сервере вам нужен метод .aggregate().

Работая с этим, я уже имел свой собственный образец данных, ожидая ввода, но он все еще служит примером. Учитывая этот первоначальный образец.

{ "petsAllowed" : true, "rooms" : 5, "type" : "townhouse" } 
{ "petsAllowed" : false, "rooms" : 4, "type" : "house"  } 
{ "petsAllowed" : true, "rooms" : 4, "type" : "townhouse" } 
{ "petsAllowed" : false, "rooms" : 4, "type" : "townhouse" } 
{ "petsAllowed" : true, "rooms" : 2, "type" : "townhouse" } 
{ "petsAllowed" : true, "rooms" : 3, "type" : "townhouse" } 
{ "petsAllowed" : true, "rooms" : 4, "type" : "house"  } 

Так что также включает в себя «тип», где мы также собираемся быть «нечетким» в матче, а не только определить «точный» совпадает. Использование трубопровода агрегации и настройки логики от ваших входов в основном так:

var roomsWanted = 4, 
    exact = "townhouse", 
    types = []; 

// Some logic to get the "fuzzy" values 
var fuzzy = [/house/] 

// Combine exact and fuzzy  
types.push(exact); 
fuzzy.forEach(function(fuzz) { 
    types.push(fuzz); 
}); 

// Perform the query 
db.houses.aggregate([ 
    // Match items you want and exclude others 
    { "$match": { 
     "type": { "$in": types }, 
     "$or": [ 
      { "rooms": { "$gte": roomsWanted } }, 
      { "rooms": roomsWanted - 1 } 
     ] 
    }}, 

    // Calculate a score 
    { "$project": { 
     "petsAllowed": 1, 
     "rooms": 1, 
     "type": 1, 
     "score": { 
      "$add": [ 
       // Exact match is higher than the fuzzy ones 
       // Fuzzy ones score lower than other possible matches 
       { "$cond": [ 
        { "$eq": [ "$type", "townhouse" ] }, 
        20, 
        2 
       ]}, 
       // When petsAllowed is true you want a weight 
       { "$cond": [ 
        "$petsAllowed", 
        10, 
        0 
       ]}, 
       // Score depending on the roomsWanted 
       { "$cond": [ 
        { "$eq": [ "$rooms", roomsWanted ] }, 
        5, 
        { "$cond": [ 
         { "$gt": [ "$rooms", roomsWanted ] }, 
         4, 
         { "$cond": [ 
          { "$eq": [ "$rooms", roomsWanted - 1 ] }, 
          3, 
          0 
         ]} 
        ]} 
       ]} 
      ] 
     } 
    }}, 
    { "$sort": { "score": -1 } }, 
]) 

Результаты вы получите затем отсортированные по генерируемый «забить», как так:

{ "petsAllowed" : true, "rooms" : 4, "type" : "townhouse", "score" : 35 } 
{ "petsAllowed" : true, "rooms" : 5, "type" : "townhouse", "score" : 34 } 
{ "petsAllowed" : true, "rooms" : 3, "type" : "townhouse", "score" : 33 } 
{ "petsAllowed" : false, "rooms" : 4, "type" : "townhouse", "score" : 25 } 
{ "petsAllowed" : true, "rooms" : 4, "type" : "house",  "score" : 17 } 
{ "petsAllowed" : false, "rooms" : 4, "type" : "house",  "score" : 7 } 

Ломая, что вниз в том, что здесь происходит, первое, что я хочу сказать, это мое собственное решение о том, что я, возможно, захочу что-нибудь, что содержит «дом» в «типе», а также любые «точные соответствия» для выбранного типа. Это произвольная логика, чтобы определить это, но дело в том, что мы рассмотрим оба примера.

Конечно, поиск будет отфильтровывать все, что вам действительно не нужно, поэтому для этого необходимо провести этап трубопровода $match. Оператор $in используется для соответствия «типу» либо точному термину «таунхаус», либо возможному совпадению регулярных выражений /house/. Это потому, что я тоже хочу этого, и ваш пробег может отличаться от того, что вы действительно хотите сделать.

Также есть условие для поиска количества комнат. Опять же произвольное решение здесь состоит в том, что я рассмотрю как все, что с четырьмя комнатами, так и выше, следовательно, условие **$gte**. Я также хочу рассмотреть вещи, у которых есть меньше места, чем было предложено. Произвольная логика снова, но просто чтобы продемонстрировать, что вы делаете, когда хотите этого.

После $match сделал «фильтрацию», вы переместите результаты на этап $project. Главное здесь, что вы хотите вычисленное значение «оценка», но вы также должны указать все полей, которые вы хотите вернуть при использовании этого этапа конвейера.

Здесь вы можете сделать выбор, по которому «вес» применяется к условиям. Оператор $add будет «суммировать» результаты, которые приводятся в качестве аргументов, которые в свою очередь производятся оператором $cond или «условным».

Это «тройной» оператор, в котором он вычисляет логическое условие «если» в качестве первого аргумента, затем либо возвращает второй аргумент true, либо третий аргумент false. Как и любой тройной, если вы хотите протестировать различные условия для «гнезда» операторов в аргументе false, чтобы «пропустить» их.

Когда-то «оценка» была определена вами $sort результатов в порядке наибольшей «оценки».

Реализация подкачки может быть сделано либо в традиционной форме путем добавления $skip и $limit стадии трубопровода в конце трубопровода или более вовлеченной «вперед пейджинг», сохраняя последнее значение (я) видел и за исключением тех из результаты поиска «оценка» $lte последний «счет», который был замечен. Это еще одна тема сама по себе, но все зависит от того, какая концепция пейджинга подходит для вашего приложения наилучшим образом.

Конечно, для некоторой логики, такой как «petsAllowed», вы хотите, чтобы эти условия вычисляли вес, когда он действительно соответствует критериям выбора, которые вы хотите. Часть красоты синтаксиса конвейера агрегации и, действительно, всего синтаксиса запросов MongoDB заключается в том, что независимо от реализации языка это просто представление о структуре данных. Таким образом, вы можете просто «построить» этапы конвейера, как требуется от ваших входов, как и любая структура данных в коде.

Это принципы, но, конечно, все идет по цене, и вычисление этих весов «на лету» - это не просто простой запрос, в котором значения можно искать в индексе.

+0

Большое вам спасибо за это! Это определенно проясняет многое. – user1883614

+0

@ user1883614 У меня было некоторое время обеда. Естественно, ваши правила взвешивания будут различаться, но по крайней мере это должен быть базовый шаблон для реализации вашей фактической логики. –

+0

Единственная проблема заключается в том, что имеется около 6 полей max, но не все будут использоваться каждый раз, когда я вызываю поиск, поэтому я посмотрю, как это сделать. – user1883614

Смежные вопросы