6

我在为我的 java 应用程序使用 ElasticSearch 时遇到了麻烦。我解释一下自己,我有一个映射,类似于:

{
"products": {
    "properties": {
        "id": {
            "type": "long",
                   "ignore_malformed": false
        },
        "locations": {
            "properties": {
                "category": {
                    "type": "long",
                   "ignore_malformed": false
                },
                "subCategory": {
                    "type": "long",
                   "ignore_malformed": false
                },
                "order": {
                    "type": "long",
                   "ignore_malformed": false
                }
            }
        },
...

因此,如您所见,我收到了由位置组成的产品列表。在我的模型中,这个位置是所有类别的产品。这意味着一个产品可以属于一个或多个类别。在每个类别中,产品都有一个订单,这是客户想要向他们展示的订单。

例如,钻石产品可以在珠宝中排名第一,但在女人中排名第三(我的例子不是那么合乎逻辑^^)。因此,当我单击珠宝时,我想显示此产品,按此特定类别中的字段 locations.order 排序。

目前,当我搜索特定类别的所有产品时,我收到的 ElasticSearch 响应类似于:

{"id":5331880,"locations":[{"category":5322606,"order":1},
{"category":5883712,"subCategory":null,"order":3},
{"category":5322605,"subCategory":6032961,"order":2},.......

是否可以通过元素 locations.order 对我正在搜索的特定类别的产品进行排序?例如,如果我查询类别 5322606,我希望获得该产品的订单 1。

非常感谢您!问候,奥利维尔。

4

2 回答 2

9

首先是术语的更正:在 Elasticsearch 中,“父/子”是指完全独立的文档,其中子文档指向父文档。父子节点存储在同一个分片上,但它们可以独立更新。

nested通过上面的示例,您可以使用文档来完成您想要实现的目标。

目前,您的locations领域是type:"object". 这意味着每个位置的值都会变平,看起来像这样:

{ 
    "locations.category": [5322606, 5883712, 5322605],
    "locations.subCategory": [6032961],
    "locations.order": [1, 3, 2]
}

换句话说,“子”字段被扁平化为多值字段,这对您没有用处,因为 和 之间没有相关category: 5322606order: 1

但是,如果您在内部更改locationstype:"nested"then ,它会将每个位置索引为单独的文档,这意味着可以使用专用的nested 查询过滤器独立查询每个位置。

默认情况下,nested查询将根据每个位置的匹配程度返回 a ,但在您的情况下,您希望从任何匹配的子_score项返回字段的最大值。order为此,您需要使用custom_score查询。

因此,让我们首先使用适当的映射创建索引:

curl -XPUT 'http://127.0.0.1:9200/test/?pretty=1'  -d '
{
   "mappings" : {
      "products" : {
         "properties" : {
            "locations" : {
               "type" : "nested",
               "properties" : {
                  "order" : {
                     "type" : "long"
                  },
                  "subCategory" : {
                     "type" : "long"
                  },
                  "category" : {
                     "type" : "long"
                  }
               }
            },
            "id" : {
               "type" : "long"
            }
         }
      }
   }
}
'

我们为您的示例文档编制索引:

curl -XPOST 'http://127.0.0.1:9200/test/products?pretty=1'  -d '
{
   "locations" : [
      {
         "order" : 1,
         "category" : 5322606
      },
      {
         "order" : 3,
         "subCategory" : null,
         "category" : 5883712
      },
      {
         "order" : 2,
         "subCategory" : 6032961,
         "category" : 5322605
      }
   ],
   "id" : 5331880
}
'

现在我们可以使用上面讨论的查询来搜索它:

curl -XGET 'http://127.0.0.1:9200/test/products/_search?pretty=1'  -d '
{
   "query" : {
      "nested" : {
         "query" : {
            "custom_score" : {
               "script" : "doc[\u0027locations.order\u0027].value",
               "query" : {
                  "constant_score" : {
                     "filter" : {
                        "and" : [
                           {
                              "term" : {
                                 "category" : 5322605
                              }
                           },
                           {
                              "term" : {
                                 "subCategory" : 6032961
                              }
                           }
                        ]
                     }
                  }
               }
            }
         },
         "score_mode" : "max",
         "path" : "locations"
      }
   }
}
'

注意:脚本中的单引号已被转义\u0027以绕过 shell 引用。该脚本实际上如下所示:"doc['locations.order'].value"

如果_score从结果中查看,您可以看到它使用order了匹配的值location

{
   "hits" : {
      "hits" : [
         {
            "_source" : {
               "locations" : [
                  {
                     "order" : 1,
                     "category" : 5322606
                  },
                  {
                     "order" : 3,
                     "subCategory" : null,
                     "category" : 5883712
                  },
                  {
                     "order" : 2,
                     "subCategory" : 6032961,
                     "category" : 5322605
                  }
               ],
               "id" : 5331880
            },
            "_score" : 2,
            "_index" : "test",
            "_id" : "cXTFUHlGTKi0hKAgUJFcBw",
            "_type" : "products"
         }
      ],
      "max_score" : 2,
      "total" : 1
   },
   "timed_out" : false,
   "_shards" : {
      "failed" : 0,
      "successful" : 5,
      "total" : 5
   },
   "took" : 9
}
于 2013-01-25T10:31:45.590 回答
0

只需添加与按子字段排序父级相关的更新版本。我们可以查询按子字段(例如“计数”)排序的父文档类型,如下所示。

https://gist.github.com/robinloxley1/7ea7c4f37a3413b1ca16

于 2016-02-29T03:37:27.837 回答