首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Elasticsearch -查找商品标签,这些标签是匹配用户标签的子集

问Elasticsearch -查找商品标签,这些标签是匹配用户标签的子集
EN

Stack Overflow用户
提问于 2017-11-24 13:32:56
回答 1查看 186关注 0票数 0
代码语言:javascript
复制
PUT /goods/goods/1
{
  "tag": ["apple","gold","4G"]
}

PUT /goods/goods/2
{
  "tag": ["apple","gold"]
}

有多个标签的商品,我们也有多个标签的用户。我们试图找到标签是用户标签子集的商品。

例如:

代码语言:javascript
复制
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 nothing

Elasticsearch能做到这一点吗?

EN

回答 1

Stack Overflow用户

发布于 2017-11-25 20:25:08

您想要实现的行为类似于Finding Multiple Exact Values中描述的行为。

由于您所展示的上一个示例,这不是直接可能的:

代码语言:javascript
复制
user ["apple"] find nothing

Elasticsearch将不得不构建一个查询find me all goods that have only one tag 'apple',而不可能直接使用倒排索引来实现。它只存储包含该标签的文档的if;该列表将包含包含该标签的所有文档,而不管它们是否还包含其他标签。有关更多详细信息,请参阅此page。

尽管有Exact Match的变通方法,但在您的示例中,您希望检索Elasticsearch中的文档,这些文档是子集,即包含来自查询的任意数量的元素,但仅此而已。与精确匹配的情况类似,它不能有效地完成。

一个脚本化的解决方案

如果您的数据允许的话,有一种可能的解决方法。例如,如果您的商品/用户标签矩阵是稀疏的(意味着它们很少共享相同的标签),您可以使用带有脚本过滤器的bool should查询来实现您的目标:

代码语言:javascript
复制
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等)。试着找出最适合你的。

希望这能有所帮助!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47466922

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档