MongoDB:在给定行之前和之后顺序返回行?

Asi*_*san 5 database search find mongodb

在MongoDB中,给定find()运算符返回一组行的游标,这是一种惯用且省时的方式来返回“上下文”行,即按顺序在该组中的每一行之前和/或之后的行?

对我来说,最简单的解释这个概念的方法是使用ack,它支持上下文搜索。给定一个文件:

line 1
line 2
line 3
line 4
line 5
line 6
line 7
line 8
Run Code Online (Sandbox Code Playgroud)

这是ack的输出:

C:\temp>ack.pl -C 2 "line 4" test.txt
line 2
line 3
line 4
line 5
line 6
Run Code Online (Sandbox Code Playgroud)

我将日志数据存储在MongoDB集合中,每行一个文档。每个日志都将每个标记化为关键字,并对这些关键字进行索引,这使我获得了便宜的全文搜索。

我执行一个沼泽标准:

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

并得到一个光标。在此阶段,不添加任何其他字段,获取上下文的方法是什么?我认为流程是这样的:

  • 对于光标中的每一行:
    • 获取_id字段,存储到x中。
    • 执行:collection.find({_ id:{'$ gt':x}})。limit(N)
      • 从每个游标中获取结果。
    • 执行:collection.find({_ id:{'$ lt':x}})。sort({_ id:1})。limit(N)
      • 从每个游标中获取结果。

对于具有R行的结果集,这需要2R + 1查询。

但是,我认为我可以权衡时间。是否可行的替代方案是在后台用上下文_id更新每一行?对于当前具有字段的给定行:

_id, contents, keywords
Run Code Online (Sandbox Code Playgroud)

我会添加一个附加字段:

_id, contents, keywords, context_ids
Run Code Online (Sandbox Code Playgroud)

然后我可以在随后的搜索中以某种方式使用这些context_ids吗?我对MongoDB MapReduce完全不熟悉,但是那也可以出现吗?

我认为最直接的方法是将实际上下文行的全文存储在每一行中,但这对我来说似乎有点粗糙。明显的优势是,单个查询可以返回我需要的上下文。

我感谢接受问题范围的所有答案。我意识到我可以带外使用Lucene或真正的全文本搜索引擎,但是我想体验一下MongoDB的优势和功能,所以我希望能得到MongoDB特定的答案。谢谢!

dcr*_*sta 3

我认为你的存储方法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]
Run Code Online (Sandbox Code Playgroud)

我想知道上下文行的集合 - 特别是您正在考虑的行之后的行可能很困难,因为任何给定行之后的行不一定存在。

另一种方法可以避免此问题(但仍然需要固定的、预先已知的上下文量),只需将上下文第一行的 _id 存储在相关行之前(即在插入时,您可以缓冲前面的 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)
Run Code Online (Sandbox Code Playgroud)

这也可以简化您的应用程序逻辑,因为您不需要将上下文与相关行重新组合,此查询将返回匹配的行和上下文行。