gpt4 book ai didi

mongodb - 按不同权重的相关性查询

转载 作者:可可西里 更新时间:2023-11-01 09:08:50 25 4
gpt4 key购买 nike

我提供了产品搜索功能,

用户可以通过多个标签进行搜索,

例如用户可以搜索“iphone,128G, usa”

如果搜索字词与标题匹配,它将得分 3 分

如果搜索词在标签中匹配,它将得分 1 分

如何重写当前查询以执行结果。

  • 文档 1 将获得:7 分
  • 文档 2 将获得:4 分

示例文档 1

"title": "iphone 6 128G",
"tag": [
"usa",
"golden",
]

示例文档 2

"title": "iphone 4 64G",
"tag": [
"usa",
"golden",
]

当前查询

  collection.aggregate(
{
"$match" => {
"tag":{ "$in"=> q_params },
}
},
{ "$unwind" => "$tag" },
{ "$match" => { "tag"=> { "$in"=> q_params } } },
{ "$group" => { "_id"=> {"title":"$title"},
"points"=> { "$sum"=>1 } } },
{ "$sort" => { "points"=> -1 } }
)

最佳答案

我认为您以错误的方式处理了这个问题,并从数据库中要求过多的“模糊匹配”。相反,考虑这个修改后的数据样本:

db.items.insert([
{
"title": "iphone 6 128G",
"tags": [
"iphone",
"iphone6",
"128G",
"usa",
"golden",
]
},
{
"title": "iphone 4 64G",
"tags": [
"iphone",
"iphone4",
"64G",
"usa",
"golden",
]
}
])

现在您考虑这样的“搜索词组”:

"iphone4 128G usa"

然后你需要实现你自己的应用程序逻辑(不是一件很难的事,只是引用主标签),它扩展成这样:

var searchedTags = ["iphone", "iphone4", "128G", "usa"]

您可以像这样构建管道查询:

db.items.aggregate([
{ "$match": { "tags": { "$in": searchedTags } } },
{ "$project": {
"title": 1,
"tags": 1,
"score": {
"$let": {
"vars": {
"matchSize":{
"$size": {
"$setIntersection": [
"$tags",
searchedTags
]
}
}
},
"in": {
"$add": [
"$$matchSize",
{ "$cond": [
{ "$eq": [
"$$matchSize",
{ "$size": "$tags" }
]},
"$$matchSize",
0
]}
]
}
}
}
}},
{ "$sort": { "score": -1 } }
])

返回这些结果:

{
"_id" : ObjectId("55b3551164518e494632fa19"),
"title" : "iphone 6 128G",
"tags" : [
"iphone",
"iphone6",
"128G",
"usa",
"golden"
],
"score" : 3
}
{
"_id" : ObjectId("55b3551164518e494632fa1a"),
"title" : "iphone 4 64G",
"tags" : [
"iphone",
"iphone4",
"64G",
"usa",
"golden"
],
"score" : 2
}

因此,“标签”匹配次数越多的人总是获胜。

但是如果把短语改成这样:

"iphone4 64G usa golden"

这导致了这样的解析标签:

var searchedTags = ["iphone", "iphone4", "64G", "usa", "golden"]

然后相同的查询管道产生这个:

{
"_id" : ObjectId("55b3551164518e494632fa1a"),
"title" : "iphone 4 64G",
"tags" : [
"iphone",
"iphone4",
"64G",
"usa",
"golden"
],
"score" : 10
}
{
"_id" : ObjectId("55b3551164518e494632fa19"),
"title" : "iphone 6 128G",
"tags" : [
"iphone",
"iphone6",
"128G",
"usa",
"golden"
],
"score" : 3
}

您不仅从一个文档中提供的标签上获得了比另一个文档更多匹配的好处,而且因为其中一个文档匹配了“所有”标签提供了额外的分数提升,进一步插入它排名比仅匹配相同数量标签的东西更高。

要分解它,首先考虑 $let那里的表达式为管道中的元素声明了一个“变量”,因此我们不会通过在多个地方为生成的 $$matchSize 值键入相同的表达式来“重复自己”。

该变量本身是通过计算 $setIntersection 的结果数组来确定的searchedTags 数组和 $tags 数组本身。 “交集”的结果只是那些匹配的项目,这为测试 $size 提供了空间那个数组的。

因此,稍后在将该匹配项的 $size 归因于“分数”时,另一个考虑因素是通过三元 $cond 给出的查看 $$matchSize 是否等于 $tags 的原始长度。如果为真,则将 $$matchSize 添加到自身(得分是“标签”长度的两倍),以便与提供的标签“完全匹配”,否则该条件的返回结果是0

$add 处理这两个数值结果生成每个文档的最终总“分数”值。


主要的一点是聚合框架缺少运算符来对标题等字符串进行任何类型的“模糊匹配”。惠斯特你可以$regex$match 内匹配阶段,因为这基本上是一个查询运算符,它只会“过滤”结果。

您可以“乱搞”它,但实际上您想要的正则表达式是为匹配的术语获得数字“分数”。这种拆分(虽然在其他语言的正则表达式运算符中可能)实际上并不可用,因此简单地“标记化”您的“标签”以进行输入并将它们与文档“标签”进行匹配更有意义。

对于“数据库”(主要是 MongoDB)来说,这是一个更好的解决方案。或者你甚至可以将它与 $text 结合起来搜索运算符结合“已解析标签”逻辑在标题上转换它自己的“分数”值,如此处所示。这为“精确匹配”提供了更多的有效性。

它可以与聚合管道结合使用,但即使它本身也不会产生不好的结果:

db.items.createIndex({ "title": "text" })

db.items.find({
"$text": { "$search": "iphone 4 64G" } },
{ "score": { "$meta": "textScore" }}
).sort({ "score": { "$meta": "textScore" } })

会产生:

{
"_id" : ObjectId("55b3551164518e494632fa1a"),
"title" : "iphone 4 64G",
"tags" : [
"iphone",
"iphone4",
"64G",
"usa",
"golden"
],
"score" : 2
}
{
"_id" : ObjectId("55b3551164518e494632fa19"),
"title" : "iphone 6 128G",
"tags" : [
"iphone",
"iphone6",
"128G",
"usa",
"golden"
],
"score" : 0.6666666666666666
}

但是如果您只想发送字符串并且不想被“标记化”逻辑所困扰,并且希望其他逻辑来归因于您的“分数”,那么请查看专用的文本搜索引擎,它们可以做得更好而不是“文本搜索”,甚至是像 MongoDB 这样的主要功能数据库的基本搜索功能。

关于mongodb - 按不同权重的相关性查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31624667/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com