PUT /goods/goods/1
{
"tag": ["apple","gold","4G"]
}
PUT /goods/goods/2
{
"tag": ["apple","gold"]
}有多个标签的商品,我们也有多个标签的用户。我们试图找到标签是用户标签子集的商品。
例如:
user ["apple","gold","4G","fruit"] find goods 1 2
user ["apple","gold","4G"] find goods 1 2
user ["apple","gold"] find goods 2
user ["apple"] find nothingElasticsearch能做到这一点吗?
发布于 2017-11-25 20:25:08
您想要实现的行为类似于Finding Multiple Exact Values中描述的行为。
由于您所展示的上一个示例,这不是直接可能的:
user ["apple"] find nothingElasticsearch将不得不构建一个查询find me all goods that have only one tag 'apple',而不可能直接使用倒排索引来实现。它只存储包含该标签的文档的if;该列表将包含包含该标签的所有文档,而不管它们是否还包含其他标签。有关更多详细信息,请参阅此page。
尽管有Exact Match的变通方法,但在您的示例中,您希望检索Elasticsearch中的文档,这些文档是子集,即包含来自查询的任意数量的元素,但仅此而已。与精确匹配的情况类似,它不能有效地完成。
一个脚本化的解决方案
如果您的数据允许的话,有一种可能的解决方法。例如,如果您的商品/用户标签矩阵是稀疏的(意味着它们很少共享相同的标签),您可以使用带有脚本过滤器的bool should查询来实现您的目标:
POST goods/goods/_search
{
"query": {
"bool": {
"filter": {
"bool": {
"must": [
{
"bool": {
"should": [
{
"term": {
"tag": {
"value": "apple"
}
}
},
{
"term": {
"tag": {
"value": "gold"
}
}
},
{
"term": {
"tag": {
"value": "4G"
}
}
}
]
}
},
{
"script": {
"script": {
"inline": "int k = 0; for (int i = 0; i < doc['tag'].length; ++i) { if (!params.user_tags.contains(doc['tag'][i])) { k +=1} } k == 0",
"lang": "painless",
"params": {
"user_tags": [
"apple",
"gold",
"4G"
]
}
}
}
}
]
}
}
}
}
}查询执行以下操作(以一种简化的方式):
should部件:匹配包含任何用户tags;script部件的所有文档:筛选出包含其他标记的文档script查询允许执行几乎任何可能的查询,但它肯定不会像内置term查询那样高效(因为它不会使用索引,而是在最坏的情况下执行完全扫描)。
其思想是同时使用term和script,并将它们合并到一个and (bool must查询)中,以便脚本化部分仅应用于可能匹配的文档。(有关查询在Elasticsearch中的应用顺序的说明可以在here中找到。)
结束语
与通常使用Elasticsearch一样,为了获得最佳性能,您可能需要重新排列数据(如添加tag_count等)。试着找出最适合你的。
希望这能有所帮助!
https://stackoverflow.com/questions/47466922
复制相似问题