ElasticSearch随机得分与加权结合使用?

4
我正在使用 Firebase 构建 iOS 应用程序,并使用 ElasticSearch 作为搜索引擎来获取更高级的查询。我正试图实现一个系统,可以根据查询从索引中获取随机记录。我已经使用 seed 和 "random_score" 函数使其工作。因此,所有文档都应该具有相等的被选中机会。是否可能添加提升或其他东西(抱歉,我是ES新手)?假设文档具有字段 "boost_enabled" 并设置为 true,则该文档将有3倍的可能性被选择,从而“增加”了随机选择的机会。理论上它应该是这样的:匹配查询的文档:
"document1"
"document2"
"document3"

它们被选中的机会相等(33%)

我希望实现的目标是,如果“document1”具有字段“boost_enabled”= true

它应该看起来像这样:

"document1"
"document1"
"document1"
"document2"
"document3"

现在,“document1”被选为随机记录的可能性增加了3倍。

非常感谢帮助。

编辑:

我想到了这样的东西,这正确吗?虽然我几乎确定它不正确...

"query" : {
        "function_score": {
            "query": {
                "bool" : {
                    "must": {
                        "match_all": {}
                    },
                    "should": [
                        { "exists" : {
                            "field" : "boost_enabled",
                            "boost" : 3
                            }
                        }
                    ]
                    "filter" : filterArray
                 }
            },

            "functions": [
                {
                    "random_score": {"seed": seed}
                }
            ]
        }
    }

/ 马兹

2个回答

2
是的,Elasticsearch 有类似的功能 - 参考Elasticsearch: Query-Time Boosting
在您的情况下,您的查询中会有一个部分,记录了您描述的标志的存在,并且这个“子查询”将具有提升。使用 `bool` 和它的 `should` 子句可能会很有用。
注意:这不完全等同于能够说匹配的文档是结果的 n 倍。
编辑:

--

编辑1:
Elasticsearch会通过Explain API告诉您它如何计算得分,这可能有助于调整参数。

--

编辑2:

我为我之前发布的内容道歉。经过进一步的思考和探索,我认为boost参数并不是所需的。虽然function_score已经有了权重的概念,但即使如此也还不够。我发现其他用户有类似于您的需求,但看起来没有提出任何好的解决方案。

参考资料:

我不认为这些帖子中提出的解决方案是完全正确的。我编写了一个快速的shell脚本,访问Elasticsearch REST API,并依赖于jq(用于处理JSON的流行CLI)进行演示:Github Gist: Flawed Attempt At Weighed Random Sampling with Elasticsearch

在脚本中,featured_flag 相当于您的 boost_enabled,而 undesired_flag 用于演示如何仅考虑索引中的一部分文档。您可以复制脚本顶部调整全局变量,如 Elasticsearch 服务器、索引等来尝试它。
关于脚本的一些注释:
  • 脚本创建了一个启用了 featured_flag 的文档和一个启用了 undesired_flag 的文档,但不应该被选择
  • TOTAL_DOCUMENTS 可用于调整创建的总文档数量(包括前两个创建的文档)
  • FEATURED_FLAG_WEIGHT 是通过 function_score 在查询时应用的权重
  • 脚本重新运行相同的查询1000次,并输出有多少次每个创建的文档作为第一个结果返回的统计信息
我想你的索引中有许多“特色”或“提升”的样本,而其他样本则不是。根据所描述的要求,选择样本的概率取决于文档的权重(例如,对于提升的文档为3,其他为1),以及您想要考虑的所有有效文档的权重总和。因此,简单的权重、提升和随机抽样似乎是不够的。
很多人已经考虑并发布了一些解决方案,用于在没有Elasticsearch的情况下进行加权随机抽样。这似乎是一个不错的尝试来解释一些方法:electric monk: Weighted Random Distribution。这里可能不太相关的算法细节,但我认为它们很有趣。
我认为理想的解决方案需要在Elasticsearch之外完成(而不涉及创建Elasticsearch插件、评分器等)。目前,以下是我能想到的最好的解决方案:
  • 一个存储在文档中的数值权重字段(可以继续使用布尔字段,但这种方式更灵活)

  • 使用聚合查询来获取一些我们需要的统计信息,向 Elasticsearch 发送初始查询

    • 可能需要使用求和聚合来计算文档概率所需的权重总和
    • 使用词项聚合来按权重计算文档数量(例如:有 m 个权重为 1 的文档,有 n 个权重为 3 的文档)
  • 在 Elasticsearch 外部(在应用程序中),选择样本
    • 在 0 到 sum_of_weights-1 的范围内生成随机数字
    • 使用聚合结果和生成的随机数来选择一个索引(参见加权随机抽样算法解决方案),该索引位于 0 到 total_valid_documents-1 的范围内(将其称为selected_index
  • 第二次向 Elasticsearch 发送请求,使用适当的过滤器仅考虑有效文档,使用sort参数保证每次运行此过程时文档集的顺序相同(可能按权重和文档 ID 排序),并将from参数设置为selected_index
与此略有关联,我发布了一个稍微不同的写作链接

但是,它会给我类似的效果吗?还是完全不现实? - Mads Odgaard
我认为你需要进行实验来看看它是否可行。如果选择了正确的随机权重和正确的增强,我认为它应该能够奏效。如果你还没有找到,可以查看“解释”功能/ Elasticsearch分配的得分的解释来帮助你。 - eemp
非常感谢您的帮助。我已经将查询添加到帖子中,这样做是正确的吗? - Mads Odgaard
嘿,谢谢!- 我目前遇到的问题是,如果在任何文档中该字段不存在,则查询不会返回任何文档。我仍然希望能够拥有其他文档,只是给具有此字段的文档更高的“机会”被选中。你能否尝试编辑我的查询,使其符合你认为的实际情况?- 所有其他过滤器和查询应匹配。该应用程序向用户显示其他用户发布的随机文档。如果用户对该文档进行了提升,则应该进行“提升”,更多人将更快地看到它。因此优先考虑。 - Mads Odgaard
@MadsOdgaard 我更新了我的帖子,并加入了更多的注释,也许提供了一个更理想的解决方案。对于最初误导您的帖子,我深表歉意 :( - eemp
显示剩余2条评论

2
在 ES 7.15 中,我使用了 {script_score} 键,下面是我的示例。
这段代码 "source": "_score + Math.random()" 将一个 0.0 -> 1.0 的随机数加到了我本来的得分中。欲了解更多信息,请查看此链接
{
    "size": { YOUR_SIZE_LIMIT },
    "query": {
        "script_score": {
            "query": {
                "query_string": {
                    "fields": [
                        "{ YOUR_FIELD_1 }^6",
                        "{ YOUR_FIELD_2 }^3",
                    ],
                    "query": "{ YOUR_SEARCH_QUERY }"
                }
            },
            "script": {
                "source": "_score + Math.random()"
            }
        }
    }
}

目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接