我使用术语查询来排除 100,000 个或更多项目的列表,因为术语查询默认只允许 65,536 个术语,ES 抛出以下错误:
条款查询请求中使用的条款数量 [115687] 已超过允许的最大值 [65536]。可以通过更改 [index.max_terms_count] 索引级别设置来设置此最大值。
解决我的问题的一种方法是增加max_terms_count,但我怀疑它会很慢。
另一种解决方案是在 PHP 中排除那些资源消耗过多的项目。
有没有更好的方法从 ES 搜索结果中排除大量项目?
我找到了解决方案,希望对那些可能面临同样问题的人有所帮助。解决方案是将大列表拆分为多个较小的列表,并将每个列表放入单独的“术语”查询中。例如,假设 max_terms_count为4,并且我们需要从搜索结果中排除 12 个项目。
$iMaxTermsCount = 4;
$arItems = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
];
if (count($arItems) <= $iMaxTermsCount) {
// Add all items to the terms query. It will produce:
// "terms": {
// "item_id": [
// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
// ]
// }
} else {
$arChunks = array_chunk($arItems, $iMaxTermsCount);
foreach ($arChunks as $ar) {
// Add some (4) items to the terms query.
}
// The loop above will produce:
// {
// "terms": {
// "item_id": [
// 1, 2, 3, 4
// ]
// }
// },
// {
// "terms": {
// "item_id": [
// 5, 6, 7, 8
// ]
// }
// },
// {
// "terms": {
// "item_id": [
// 9, 10, 11, 12
// ]
// }
// }
}
Run Code Online (Sandbox Code Playgroud)
最终的 JSON 对象将如下所示:
{
"query": {
"bool": {
"must_not": [
{
"bool": {
"should": [
{
"terms": {
"item_id": [
1, 2, 3, 4
]
}
},
{
"terms": {
"item_id": [
5, 6, 7, 8
]
}
},
{
"terms": {
"item_id": [
9, 10, 11, 12
]
}
}
]
}
}
]
}
}
}
Run Code Online (Sandbox Code Playgroud)
上面的查询将排除所有项目,而不会引发任何错误。