ElasticSearch:按嵌套文档的值排序

Oli*_*r.G 6 java sorting elasticsearch

我在为我的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
                }
            }
        },
...
Run Code Online (Sandbox Code Playgroud)

因此,正如您所看到的,我收到了一个由位置组成的产品列表.在我的模型中,这些位置是所有类别的产品.这意味着产品可以是1个或更多类别.在此类别的每个类别中,产品都有一个订单,即客户希望显示订单的订单.

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

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

{"id":5331880,"locations":[{"category":5322606,"order":1},
{"category":5883712,"subCategory":null,"order":3},
{"category":5322605,"subCategory":6032961,"order":2},.......
Run Code Online (Sandbox Code Playgroud)

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

非常感谢你事先!此致,奥利维尔.

DrT*_*ech 9

首先是术语的更正:在Elasticsearch中,"父/子"指的是完全独立的文档,其中子文档指向父文档.父级和子级存储在同一个分片上,但可以单独更新.

通过上面的示例,您尝试实现的目标可以通过nesteddocs 完成.

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

{ 
    "locations.category": [5322606, 5883712, 5322605],
    "locations.subCategory": [6032961],
    "locations.order": [1, 3, 2]
}
Run Code Online (Sandbox Code Playgroud)

换句话说,"sub"字段变平为多值字段,这对你没用,因为category: 5322606和之间没有相关性order: 1.

但是,如果您locations在type:"nested"内部进行更改,则会将每个位置编入索引作为单独的文档,这意味着可以使用专用nested 查询和过滤器独立查询每个位置.

默认情况下,nested查询将_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"
            }
         }
      }
   }
}
'
Run Code Online (Sandbox Code Playgroud)

我们将您的示例文档编入索引:

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
}
'
Run Code Online (Sandbox Code Playgroud)

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

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"
      }
   }
}
'
Run Code Online (Sandbox Code Playgroud)

注意:脚本中的单引号已被转义为\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
}
Run Code Online (Sandbox Code Playgroud)