查找Mongodb字段中出现次数最多的单词

Find the most occurrence words exist in a field Mongodb

本文关键字:单词 Mongodb 字段 查找      更新时间:2023-09-26

我有一个集合A和数组B,其结构如下:

A:

{
    "_id" : ObjectId("5160757496cc6207a37ff778"),
    "name" : "Pomegranate Yogurt Bowl",
    "description" : "A simple breakfast bowl made with Greek yogurt, fresh pomegranate juice, puffed quinoa cereal, toasted sunflower seeds, and honey."
},
{
  "_id": ObjectId("5160757596cc62079cc2db18"),
  "name": "Krispy Easter Eggs",
  "description": "Imagine the Easter Bunny laying an egg.     Wait. That’s not anatomically possible.     And anyway, the Easter Bunny is a b..."
}

B:

var names = ["egg", "garlic", "cucumber", "kale", "pomegranate", "sunflower", "fish", "pork", "apple", "sunflower", "strawberry", "banana"]

我的目标是从A返回一个文档,它在数组B中出现的单词最多。在这种情况下,它应该返回第一个"_id" : ObjectId("5160757496cc6207a37ff778")

我不知道如何着手解决这个问题:

这不起作用:

db.A.find({
    "description": {
      "$in": names
    }
  }, function(err, data) {
    if (err) console.log(err);
    console.log(data);
  });

这取决于你想要抛出的"单词"的类型,以及它们是否是被视为"停止单词"的东西,如"a""the""with"等,或者这些东西的数量是否真的无关紧要。

如果它们无关紧要,那么考虑$text索引并进行搜索。

第一个索引:

db.A.createIndex({ "name": "text", "description": "text" })

然后构建搜索:

var words = [
  "egg", "garlic", "cucumber", "kale", "pomegranate",
  "sunflower", "fish", "pork", "apple", "sunflower",
  "strawberry", "banana"
];
var search = words.join(" ")
db.A.find(
    { "$text": { "$search": search } },
    { "score": { "$meta": "textScore" } }
).sort({ "score": { "$meta": "textScore" }}).limit(1)

返回第一个文档,如下所示:

{
    "_id" : ObjectId("5160757496cc6207a37ff778"),
    "name" : "Pomegranate Yogurt Bowl",
    "description" : "A simple breakfast bowl made with Greek yogurt, fresh pomegranate juice, puffed quinoa cereal, toasted sunflower seeds, and honey.",
    "score" : 1.7291666666666665
}

另一方面,如果你需要计算"停止单词",那么mapReduce可以为你找到结果:

db.A.mapReduce(
  function() {
    var words = [
      "egg", "garlic", "cucumber", "kale", "pomegranate",
      "sunflower", "fish", "pork", "apple", "sunflower",
      "strawberry", "banana"
    ];
    var count = 0;
    var fulltext = this.name.toLowerCase() + " " + this.description.toLowerCase();
    // Increment count by number of matches
    words.forEach(function(word) {
      count += ( fulltext.match(new RegExp(word,"ig")) || [] ).length;
    });
    emit(null,{ count: count, doc: this });
  },
  function(key,values) {
    // Sort largest first, return first
    return values.sort(function(a,b) {
      return a.count < b.count;
    })[0];
  },
  { "out": { "inline": 1 } }
)

结果:

{
    "_id" : null,
    "value" : {
        "count" : 4,
        "doc" : {
            "_id" : ObjectId("5160757496cc6207a37ff778"),
            "name" : "Pomegranate Yogurt Bowl",
            "description" : "A simple breakfast bowl made with Greek yogurt, fresh pomegranate juice, puffed quinoa cereal, toasted sunflower seeds, and honey."
        }
    }
}

因此,"文本"索引方法是根据匹配数量进行"加权",然后只返回最大的加权匹配。

mapReduce操作遍历每个文档并计算出一个分数。然后"减少者"会对结果进行排序,只保留得分最高的一个。

请注意,可以多次调用"reducer",因此这"不会"尝试同时对集合中的所有文档进行排序。但它仍然是真正的"蛮力"。