【问题标题】:Sorting by relevance with MongoDB按与 MongoDB 的相关性排序
【发布时间】:2012-09-28 01:14:00
【问题描述】:

我有以下形式的文档集合:

{ _id: ObjectId(...)
, title: "foo"
, tags: ["bar", "baz", "qux"] 
}

查询应该找到所有带有这些标签的文档。我目前使用这个查询:

{ "tags": { "$in": ["bar", "hello"] } }

而且它有效;返回所有标记为“bar”或“hello”的文档。

但是,我想按相关性进行排序,即,匹配的标签越多,文档在结果中出现的时间就越早。例如,对于查询["bar", "hello"],结果中标记为["bar", "hello", "baz"] 的文档应高于标记为["bar", "baz", "boo"] 的文档。我怎样才能做到这一点?

【问题讨论】:

    标签: mongodb sorting


    【解决方案1】:

    MapReduce 并在客户端执行会太慢 - 您应该使用聚合框架(MongoDB 2.2 中的新功能)。

    它可能看起来像这样:

    db.collection.aggregate([
       { $match : { "tags": { "$in": ["bar", "hello"] } } },
       { $unwind : "$tags" },
       { $match : { "tags": { "$in": ["bar", "hello"] } } },
       { $group : { _id: "$title", numRelTags: { $sum:1 } } },
       { $sort : { numRelTags : -1 } }
       //  optionally
       , { $limit : 10 }
    ])
    

    请注意,第一个和第三个管道成员看起来相同,这是有意和需要的。以下是这些步骤的作用:

    1. 只传递带有“bar”或“hello”标签的文档。
    2. 展开标签数组(意味着每个标签元素拆分为一个文档
    3. 只传递“bar”或“hello”标签(即丢弃其余标签)
    4. 按标题分组(也可以按“$_id”或原始文档的任何其他组合 加起来它有多少个标签(“bar”和“hello”)
    5. 按相关标签数量降序排列
    6. (可选)将返回的集合限制为前 10 个。

    【讨论】:

    • 我认为是 { $unwind: "$tags" } 而不是 { $unwind : {"$tags"} }
    • 你知道什么 - 你是对的,四年来第一个注意到的? :)
    • 我想。顺便说一句,惊人的答案-巨大的帮助。谢谢。
    • 在新版本中,执行此操作的管道更短 - 阶段更少。我想我也应该将其添加到答案中。
    • 如果您有时间,我将不胜感激
    【解决方案2】:

    您可能会使用 MapReduce 来做类似的事情。您将在 Map 步骤中处理每个文档,确定有多少标签与查询匹配,并分配一个分数。然后您可以根据该分数进行排序。

    http://www.mongodb.org/display/DOCS/MapReduce

    【讨论】:

      【解决方案3】:

      查询后应该做一些复杂的事情。通过 db.eval 的服务器端(如果您的客户端支持此)或只是客户端。这是您正在寻找的示例。

      它将检索所有带有您指定标签的帖子,然后根据匹配的数量对它们进行排序。

      删除 db.eva( 部分并将其翻译成您的客户端用来查询以获得客户端效果的语言(

      db.eval(function () {
          var tags = ["a","b","c"];
          return db.posts.find({tags:{$in:tags}}).toArray().sort(function(a,b){
      
              var matches_a = 0;
              var matches_b = 0;
              a.tags.forEach(function (tag) {
                  for (t in tags) {
                      if (tag == t) {
                          matches_a++;
                      } else {
                          matches_b++;
                      }
                  }
              });
      
              b.tags.forEach(function(tag) {
                  for (t in tags) {
                      if (tag == t) {
                          matches_b++;
                      } else {
                          matches_a++;
                      }
                  }
              });
              return matches_a - matches_b;
          });
      });
      

      【讨论】:

      • 这对于大型收藏来说很慢,所以我会尝试提出另一个答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-20
      • 1970-01-01
      • 1970-01-01
      • 2011-01-26
      • 2017-01-01
      • 1970-01-01
      相关资源
      最近更新 更多