2016-06-28 5 views
4

Я изо всех сил найти решение проблемы с Монго DB:MongoDB - Сортировка по вычисляемое поле

мне нужно выполнить запрос на коллекции с высокой записи/чтения соотношение. Запрос состоит в сортировке документов по полю, которое получено из других полей , принадлежащих одному и тому же документу. Кроме того, одно из этих полей - это размер массива, что делает его еще сложнее.

Простой пример:

D1 - { _id: 1, field: 1, array_field: [a,b,c,d] } -> score = 1 + 4 = 5 
D2 - { _id: 2, field: 2, array_field: [a,b] }  -> score = 2 + 2 = 4 

Ожидаемый результат:

D1 - { _id: 2, score: 4 } 
D2 - { _id: 1, score: 5 } 

(Счет не требуется в результирующем)

Растворы я пытался до сих пор:

  1. A dd оценка как поле документа, которое постоянно обновляется, другие поля обновляются. Проблемы:

    • Это не представляется возможным параметризацию запроса (настройки) после того, как счет был вычисленного
    • Это дорого, так как индекс на счете должен быть обновлен очень часто
  2. Создайте конвейер агрегации, который упрощает разработку и решает проблему параметризации. Тем не менее, падение производительности на самом деле очень велико. Mongo не может полагаться на индексы использования вычисляемых полей, вызывая проблемы с памятью (ошибка запроса 100 МБ). Возможное решение - включить флаг allowDiskUse. Однако запрос будет слишком медленным.

Update: я хотел бы указать на то, что запрос будет работать около 10 раз в секунду. Поэтому предварительное вычисление и хранение оценки в другом документе может оказаться нецелесообразным решением.

Pratical Use: так как проблема очень сложная. Позвольте мне дать вам немного больше контекста. У меня есть документ с сообщениями (например, сообщения facebook). Я сортирую данные по дате создания и последнему обновлению. Я хотел бы иметь возможность сортировать сообщения по «горячей», что определяется оценкой, о которой я говорил. Я думал, что интересный способ вычислить счет может быть следующим:

score = a * likes - b * dislikes + c * num_comments + d * (now - creation_date) 

где a, b, c и d являются параметры можно изменить для настройки алгоритма. likes и dislikes - это массивы ObjectID s, ссылающиеся на пользователей, а num_comments - это просто количество комментариев. Запрос выполняется для предоставления ответа конечной точке REST. Дальнейшие операции: Запрос -> Запрос -> Ответ.

Имеете ли вы опыт работы с производными/агрегированными полями? Спасибо!

+1

Когда я столкнулся с подобной проблемой некоторое время назад, я закончил тем, что задерживал отчет. Я создал новую коллекцию с агрегацией и $ out, у которой не было других записей, поэтому я мог использовать индексы для ее оптимизации. Я не уверен, что это было оптимальное решение, но это сработало для меня. – Tiramisu

ответ

0

Это похоже на сложную проблему.

этот запрос выполнит эту работу, но я хотел бы услышать от вас о производительности.

db.perlz.aggregate([ 
// {$match:{whatever is needed here}} 
     { 
      $project : { 
       _id : 1, 
       score : { 
        $sum : [{ 
          "$size" : "$array_field" 
         }, "$field"] 
       } 
      } 
     }, { 
      $sort : { 
       score : 1 
      } 
     } 

    ]) 

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

EDIT

В соответствии с вашим обновления, я задаюсь вопросом, если эти шаги могут быть применимы к этой проблеме:

  1. структура обновление документа, чтобы иметь два типа подобных: processed и new. Processed похоже на то, что было добавлено в документ для оценки работником (что влияет на likes, dislikes, numComments полей) и настройкой оценки - тогда нам нужно рассчитать значение delta/difference.

  2. попытаться определить самый низкий входной набор на основе предыдущей точки (предварительно вычисленных баллов)

  3. Предел вывода к известному количеству документов (осуществления персонального вызова)

В соответствии с динамическим значением поля - нет большого количества вычислений, необходимых для получения оценки. Можно было бы рассмотреть поля проекта, которые используются при вычислении, и _id, а затем использовать $lookup как последний этап и родительский документ macz с забитым и отсортированным результатом.

Любые комментарии приветствуются!

+0

К сожалению, это то, что я сделал. Это приводит к ошибке «100MB query», потому что он не может сортировать с использованием индекса. –

+0

ОК, что является следующим шагом в процессе с этим выходом? – profesor79

+0

Я обновил вопрос с большим контекстом о том, почему нам нужен такой запрос. –

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