MongoDB: возвращать строки последовательно до и после данной строки? - PullRequest
5 голосов
/ 02 марта 2012

В MongoDB, учитывая оператор find (), который возвращает курсор для набора строк, что является идиоматическим и эффективным по времени способом, чтобы возвращать «контекстные» строки, то есть строки последовательно до и / или после каждой строкив наборе?

Для меня самый простой способ объяснить эту концепцию - использовать ack , который поддерживает контекстный поиск.Имеется файл:

line 1
line 2
line 3
line 4
line 5
line 6
line 7
line 8

Это вывод команды ack:

C:\temp>ack.pl -C 2 "line 4" test.txt
line 2
line 3
line 4
line 5
line 6

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

Я выполняю стандарт болота:

collection.find({keywords: {'$all': ['key1', 'key2']}}, {}).sort({datetime: -1});

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

  • Для каждой строки в курсоре:
    • Получить поле _id, сохранить в x.
    • execute: collection.find({_id: {'$ gt': x}}). limit (N)
      • Получите результаты от каждого из этих курсоров.
    • execute: collection.find ({_ id: {'$ lt': x}}). sort ({_ id: 1}). limit (N)
      • Получить результаты от каждого из этих курсоров.

Для результирующего набора с R строками это требует 2R + 1 запросов.

Однако я думаю, что могу обменять пространство на время.Является ли возможной альтернативой обновление каждой строки с ее контекстом _id на заднем плане?Для данной строки, которая в настоящее время имеет поля:

_id, contents, keywords

Я бы добавил дополнительное поле:

_id, contents, keywords, context_ids

, а затем в последующем поиске я мог бы каким-то образом использовать эти context_ids, ясчитать?Я еще совсем не знаком с MongoDB MapReduce, но может ли это также войти в картину?

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

Я ценю все ответы, которые принимают суть вопроса.Я понимаю, что могу использовать Lucene или реальный полнотекстовый поисковый движок вне диапазона, но я пытаюсь почувствовать грани и возможности MongoDB, поэтому я был бы признателен за ответы, специфичные для MongoDB.Спасибо!

1 Ответ

3 голосов
/ 02 марта 2012

Я думаю, что ваш подход к хранению context_ids или что-то в этом роде может быть лучшим вариантом.Если вы можете сохранить context_ids всех строк контекста, которые вам понадобятся (это предполагает, что это контекст фиксированного размера - скажем, 5 строк до и после), то вы можете запросить все строкииспользование контекста $in:

# pseudocode
for each matching row:
    context_rows = db.logs.find({_id: {$in: row['context_ids']}}).sort({_id: 1})
    row_with_context = [context_rows_before_row] + row + [context_rows_after_row]

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

Альтернатива, которая позволит избежать этой проблемы (но все еще требует фиксированного, заранее определенного количества контекста), это просто сохранить _id ofпервая строка контекста перед рассматриваемой строкой (т. е. при вставке вы можете буферизовать предыдущие N строк, где N - количество контекста) - вызовите это first_context_id - и затем запросите:

# pseudocode
for each matching row:
    rows_with_context = db.logs.find({_id: {$gte: row['first_context_id']}}).sort({_id: 1}).limit(N * 2 + 1)

Это также может упростить логику вашего приложения, поскольку вам не нужно повторно собирать контекст с рассматриваемой строкой, этот запрос будет возвращать как совпадающую строку, так и строки контекста.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...