我在为我的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
}
}
},
...
因此,正如您所看到的,我收到了一个由位置组成的产品列表。在我的模型中,这些位置是所有类别的产品。这意味着产品可以是1个或更多类别。在此类别的每个类别中,产品都有一个订单,即客户想要显示的订单。
例如,钻石产品在珠宝首饰中排名第一,但在女士中排名第三(我的例子不是那么逻辑^^)。 所以,当我点击珠宝时,我想展示这个产品,按照特定类别的字段location.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.
事先非常感谢! 问候, 奥利弗。
答案 0 :(得分:9)
首先修正术语:在Elasticsearch中,“父/子”指的是完全独立的文档,其中子文档指向父文档。父级和子级存储在同一个分片上,但可以单独更新。
通过上面的示例,您可以使用nested
文档完成您要实现的目标。
目前,您的locations
字段属于type:"object"
。这意味着每个位置的值变平,看起来像这样:
{
"locations.category": [5322606, 5883712, 5322605],
"locations.subCategory": [6032961],
"locations.order": [1, 3, 2]
}
换句话说,“子”字段会变平为多值字段,这对您没用,因为category: 5322606
和order: 1
之间没有相关性。
但是,如果您将locations
更改为type:"nested"
,那么它会在内部将每个位置编入索引作为单独的文档,这意味着可以使用专用的nested
{独立查询每个位置{3}}和query。
默认情况下,nested
查询会根据每个位置的匹配程度返回_score
,但在您的情况下,您希望从任意位置返回order
字段的最高值匹配孩子。为此,您需要使用filter查询。
让我们首先创建具有适当映射的索引:
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
}
答案 1 :(得分:0)
只需添加与子字段排序父项相关的更新版本。 我们可以查询按子字段排序的父文档类型('count',例如),类似如下。