在Elasticsearch中可以按范围排序吗?

Mir*_*ate 9 sorting range elasticsearch

当我执行以下查询时:

{
  "query": {
    "bool": {
      "filter": [
        {
          "match": {
            "my_value": "hi"
          }
        },
        {
          "range": {
            "my_range": {
              "gt": 0,
              "lte": 200
            }
          }
        }
      ]
    }
  },
  "sort": {
    "my_range": {
      "order": "asc",
      "mode": "min"
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我得到错误:

"caused_by": {
  "type": "illegal_argument_exception",
  "reason": "Fielddata is not supported on field [my_range] of type [long_range]"
}
Run Code Online (Sandbox Code Playgroud)

如何使range数据类型可排序?这可能吗?

Elasticsearch版本:5.4,但是我想知道是否可以使用任何版本。

更多的上下文

并非别名/索引中的所有文档都具有范围字段。但是,查询过滤器仅包括具有该字段的文档。

Kam*_*mal 1

我认为您正在寻找的是基于排序,difference of the range因为我不确定简单地对任何范围值进行排序是否有意义。

例如,如果一个文档的范围是,100, 300而另一个200, 600文档的范围是,那么您可能希望根据差异进行排序,例如,您希望较小的范围出现,即300-100 = 200出现在顶部。

如果是这样,我已经使用了下面的无痛脚本并实现了基于脚本的排序

根据范围差异排序

POST <your_index_name>/_search
{  
   "query":{  
      "match_all":{  

      }
   },
   "sort":{  
      "_script":{  
         "type":"number",
         "script":{  
            "lang":"painless",
            "inline":"params._source.my_range.lte-params._source.my_range.gte"
         },
         "order":"asc"
      }
   }
} 
Run Code Online (Sandbox Code Playgroud)

请注意,在这种情况下,排序不会基于 的任何字段值,my_range而仅基于它们的差异。如果您想根据lte、 、等字段进一步排序ltgte或者gt您可以使用多个脚本实现排序,如下所示:

根据范围+范围字段的差异进行排序(my_range.lte)

POST <your_index_name>/_search
{  
   "query":{  
      "match_all":{  

      }
   },
   "sort":[  
      {  
         "_script":{  
            "type":"number",
            "script":{  
               "lang":"painless",
               "inline":"params._source.my_range.lte - params._source.my_range.gte"
            },
            "order":"asc"
         }
      },
      {  
         "_script":{  
            "type":"number",
            "script":{  
               "lang":"painless",
               "inline":"params._source.my_range.lte"
            },
            "order":"asc"
         }
      }
   ]
}
Run Code Online (Sandbox Code Playgroud)

因此,在这种情况下,即使对于两个文档,范围相同,较小的文档my_range.lte也会首先出现。

根据范围字段排序

但是,如果您只想根据范围值之一进行排序,则可以使用以下查询。

POST <your_index_name>/_search
{  
   "query":{  
      "match_all":{  

      }
   },
   "sort":{  
      "_script":{  
         "type":"number",
         "script":{  
            "lang":"painless",
            "inline":"params._source.my_range.lte"
         },
         "order":"asc"
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

更新了答案以管理无范围的文档

这是针对场景的,根据范围差异排序 + Range.lte 或 Range.lt(以存在者为准)

下面的代码它的作用是,

  • 检查文档是否有my_range字段
  • 如果没有,那么默认情况下它将返回Long.MAX_VALUE。这意味着如果您按 asc 排序,该文档应该最后返回。
  • 此外,它会检查文档是否具有lteorlt并使用该值作为high。请注意,默认high值为Long.MAX_VALUE
  • 类似地,它会检查文档是否具有gteorgt并使用该值作为low。的默认low值为0
  • 现在计算high - low将应用排序的值。

更新的查询

POST <your_index_name>/_search
{  
   "size":100,
   "query":{  
      "match_all":{  

      }
   },
   "sort":[  
      {  
         "_script":{  
            "type":"number",
            "script":{  
               "lang":"painless",
               "inline":""" 
              if(params._source.my_range==null){ 
                return Long.MAX_VALUE; 
              } else { 

                long high = Long.MAX_VALUE; 
                long low = 0L; 

                if(params._source.my_range.lte!=null){ 
                  high = params._source.my_range.lte; 
                } else if(params._source.my_range.lt!=null){ 
                  high = params._source.my_range.lt; 
                } 

                if(params._source.my_range.gte!=null){ 
                  low = params._source.my_range.gte; 
                } else if (params._source.my_range.gt==null){ 
                  low = params._source.my_range.gt; 
                } 

              return high - low; 

              } 
                """
            },
            "order":"asc"
         }
      },
      {  
         "_script":{  
            "type":"number",
            "script":{  
               "lang":"painless",
               "inline":""" 
                if(params._source.my_range==null){ 
                  return Long.MAX_VALUE; 
                } 

                long high = Long.MAX_VALUE; 
                if(params._source.my_range.lte!=null){ 
                  high = params._source.my_range.lte; 
                } else if(params._source.my_range.lt!=null){ 
                  high = params._source.my_range.lt; 
                } 
                  return high;"""
            },
            "order":"asc"
         }
      }
   ]
}
Run Code Online (Sandbox Code Playgroud)

这应该适用于 ES 5.4。希望能帮助到你!