Search Type
在执行分布式搜索时,可以执行不同的执行路径。分布式搜索操作需要分散到所有相关的分片中,然后收集所有的结果。在执行分散/聚集类型执行时,有几种方法可以做到这一点,特别是使用搜索引擎。
执行分布式搜索时的一个问题是从每个分片中检索多少结果。例如,如果我们有10个分片,第1个分片可能包含0到10之间最相关的结果,其他分片的结果排在后面。因此,在执行请求时,我们需要从所有分片中获取从0到10的结果,对它们进行排序,然后返回结果(如果我们想确保正确的结果)。
另一个与搜索引擎相关的问题是,每个分片都独立存在。当对特定分片执行查询时,它不考虑来自其他分片的词汇频率和其他搜索引擎信息。如果我们想要支持准确的排名,首先需要从所有分片中收集词汇频率来计算全局词汇频率,然后使用这些全局频率对每个分片执行查询。
此外,由于需要对结果进行排序,在维护正确的排序行为的同时,返回一个大型文档集,甚至滚动它,可能是一个非常昂贵的操作。对于较大的滚动结果集,如果返回文档的顺序不重要,则最好按_doc排序。
Elasticsearch非常灵活,允许控制每次搜索请求执行的搜索类型。可以通过在查询字符串中设置search_type参数来配置类型。类型是:
Query Then Fetch
参数值:query_then_fetch。
请求分两个阶段处理。在第一个阶段,查询被转发给所有相关的分片。每个分片执行搜索并生成一个排序后的结果列表,该列表位于该分片的本地。每个分片向协调节点返回足够的信息,使其能够合并并将切分级别的结果重新排序为全局排序的结果集(最大长度size)。
在第二阶段中,协调节点仅从相关分片请求文档内容(如果有突出显示的片段,则突出显示)。
注意: 如果您没有在请求中指定search_type,那么这是默认设置。
Dfs, Query Then Fetch
参数值:dfs_query_then_fetch。
和”Query Then Fetch”一样,除了一个初始的分散阶段,该阶段运行并计算分布式词汇频率,以获得更准确的评分。
Sequence Numbers and Primary Term
返回每次搜索命中的序列号和上次修改的主要项。有关详细信息,请参阅乐观并发控制。
GET /_search
{
"seq_no_primary_term": true,
"query" : {
"term" : { "user" : "kimchy" }
}
}
Sort
允许您在特定字段上添加一个或多个排序。每一种排序都可以颠倒。sort是在每个字段级别上定义的,具有特殊的字段名_score按分数排序,_doc按索引顺序排序。
假设索引映射如下:
PUT /my_index
{
"mappings": {
"properties": {
"post_date": { "type": "date" },
"user": {
"type": "keyword"
},
"name": {
"type": "keyword"
},
"age": { "type": "integer" }
}
}
}
GET /my_index/_search
{
"sort" : [
{ "post_date" : {"order" : "asc"}},
"user",
{ "name" : "desc" },
{ "age" : "desc" },
"_score"
],
"query" : {
"term" : { "user" : "kimchy" }
}
}
doc除了是最有效的排序顺序之外,没有真正的用例。因此,如果您不关心返回文档的顺序,那么应该按_doc排序。这在 scrolling时尤其有用。
Sort Values
返回的每个文档的排序值也作为响应的一部分返回。
Sort Order
order选项可以有以下值:
asc 升序排序
desc 降序排列
在_score上排序时,顺序默认为desc,在其他任何东西上排序时,顺序默认为asc。
Sort mode option
Elasticsearch支持按数组或多值字段排序。mode选项控制选择哪个数组值对其所属的文档进行排序。模式选项可以有以下值:
min 选择最小的值。
max 选择最高的值。
sum 使用所有值的和作为排序值。仅适用于基于数字的数组字段。
avg 使用所有值的平均值作为排序值。仅适用于基于数字的数组字段
median 使用所有值的中值作为排序值。仅适用于基于数字的数组字段。
升序排序的默认排序模式是min—选择最小值。按降序排列的默认排序模式是max—选择最大值。
Sort mode example usage
在下面的示例中,字段price每个文档有多个价格。在这种情况下,将根据每个文档的平均价格按升序对结果命中进行排序。
PUT /my_index/_doc/1?refresh
{
"product": "chocolate",
"price": [20, 4]
}
POST /_search
{
"query" : {
"term" : { "product" : "chocolate" }
},
"sort" : [
{"price" : {"order" : "asc", "mode" : "avg"}}
]
}
Sorting numeric fields
对于数值字段,也可以使用numeric_type选项将值从一种类型转换为另一种类型。该选项接受以下值:["double"、"long"、"date"、"date_nanos"],如果sort字段在某些索引上的映射不同,则可用于跨索引搜索。
例如,考虑这两个指数:
PUT /index_double
{
"mappings": {
"properties": {
"field": { "type": "double" }
}
}
}
PUT /index_long
{
"mappings": {
"properties": {
"field": { "type": "long" }
}
}
}
由于字段在第一个索引中映射为double,在第二个索引中映射为long,因此不可能使用该字段对默认情况下同时查询两个索引的请求进行排序。但是,您可以使用numeric_type选项强制类型到其中一个或另一个,以便为所有索引强制一个特定的类型:
POST /index_long,index_double/_search
{
"sort" : [
{
"field" : {
"numeric_type" : "double"
}
}
]
}
在上面的示例中,index_long索引的值被转换为double,以便与index_double索引生成的值兼容。也可以将浮点字段转换为long,但是注意,在这种情况下,浮点被小于或等于参数的最大值(如果值是负数,则大于或等于)所替代,并且等于一个数学整数。
此选项还可用于将使用毫秒分辨率的日期字段转换为具有纳秒分辨率的date_nanos字段。例如,考虑这两个指数:
PUT /index_double
{
"mappings": {
"properties": {
"field": { "type": "date" }
}
}
}
PUT /index_long
{
"mappings": {
"properties": {
"field": { "type": "date_nanos" }
}
}
}
这些索引中的值以不同的分辨率存储,因此对这些字段进行排序将始终对date_nanos(升序)之前的日期进行排序。 使用numeric_type类型选项可以为排序设置单个分辨率,设置为date会将date_nanos转换为毫秒分辨率,而date_nanos会将date字段中的值转换为纳秒分辨率:
POST /index_long,index_double/_search
{
"sort" : [
{
"field" : {
"numeric_type" : "date_nanos"
}
}
]
}
警告: 为了避免溢出,对date_nanos的转换不能应用于1970年以前和2262之后的日期,因为纳秒表示为long。
Sorting within nested objects.
Elasticsearch还支持按一个或多个嵌套对象中的字段排序。嵌套字段支持的排序有一个嵌套排序选项,具有以下属性:
path
定义要排序的嵌套对象。实际的sort字段必须是这个嵌套对象中的直接字段。按嵌套字段排序时,必须使用此字段。
filter
一个嵌套路径内的内部对象应匹配的过滤器,以便通过排序考虑其字段值。 常见的情况是在嵌套过滤器或查询中重复查询/过滤。 默认情况下,没有nested_filter处于活动状态。
max_children
在选择排序值时,每个根文档要考虑的子文档的最大数量。默认为无限。
nested
与顶级嵌套相同,但适用于当前嵌套对象中的另一个嵌套路径。
警告: Elasticsearch 6.1之前的嵌套排序选项
nested_path和nested_filter选项已经被弃用,取而代之的是上面记录的选项。
Nested sorting examples
在下面的示例中,offer是一个嵌套类型的字段。需要指定嵌套路径;否则,Elasticsearch不知道需要在什么嵌套级别上捕获排序值。
POST /_search
{
"query" : {
"term" : { "product" : "chocolate" }
},
"sort" : [
{
"offer.price" : {
"mode" : "avg",
"order" : "asc",
"nested": {
"path": "offer",
"filter": {
"term" : { "offer.color" : "blue" }
}
}
}
}
]
}
在下面的示例中,父字段和子字段的类型是嵌套的。需要在每个级别指定nested_path;否则,Elasticsearch不知道需要在什么嵌套级别上捕获排序值。
POST /_search
{
"query": {
"nested": {
"path": "parent",
"query": {
"bool": {
"must": {"range": {"parent.age": {"gte": 21}}},
"filter": {
"nested": {
"path": "parent.child",
"query": {"match": {"parent.child.name": "matt"}}
}
}
}
}
}
},
"sort" : [
{
"parent.child.age" : {
"mode" : "min",
"order" : "asc",
"nested": {
"path": "parent",
"filter": {
"range": {"parent.age": {"gte": 21}}
},
"nested": {
"path": "parent.child",
"filter": {
"match": {"parent.child.name": "matt"}
}
}
}
}
}
]
}
在按脚本排序和按地理距离排序时,也支持嵌套排序。
Missing Values
缺少参数指定了如何处理缺少sort字段的文档:可以将缺少的值设置为_last、_first或自定义值(将用于缺少文档的排序值)。默认值是_last。
例如:
GET /_search
{
"sort" : [
{ "price" : {"missing" : "_last"} }
],
"query" : {
"term" : { "product" : "chocolate" }
}
}
注意:如果嵌套的内部对象与nested_filter不匹配,则使用缺失的值。
Ignoring Unmapped Fields
默认情况下,如果没有与字段关联的映射,搜索请求将失败。unmapped_type选项允许您忽略没有映射的字段,并且不按它们排序。此参数的值用于确定要发出的排序值。下面是一个如何使用它的例子:
GET /_search
{
"sort" : [
{ "price" : {"unmapped_type" : "long"} }
],
"query" : {
"term" : { "product" : "chocolate" }
}
}
如果查询的任何索引没有price映射,则Elasticsearch将处理它,就像有long类型的映射一样,该索引中的所有文档都没有该字段的值。
Geo Distance Sorting
允许按_geo_distance排序。 下面是一个示例,假设pin.location是geo_point类型的字段:
GET /_search
{
"sort" : [
{
"_geo_distance" : {
"pin.location" : [-70, 40],
"order" : "asc",
"unit" : "km",
"mode" : "min",
"distance_type" : "arc",
"ignore_unmapped": true
}
}
],
"query" : {
"term" : { "user" : "kimchy" }
}
}
distance_type
如何计算距离。可以是arc(默认值),也可以是plane(速度更快,但在长距离和接近极点时不准确)。
mode
如果某个字段有多个地理位置,该怎么办。 默认情况下,按升序排序时考虑最短距离,按降序排序时考虑最长距离。 支持的值是min,max,median和avg。
unit
计算排序值时使用的单位。 默认值为m(米)。
ignore_unmapped
指示是否应将未映射的字段视为丢失的值。将其设置为true相当于在字段sort中指定unmapped_type。默认值为false(未映射的字段导致搜索失败)。
注意: 地理距离排序不支持可配置的缺失值:当文档没有用于距离计算的字段的值时,该距离总是被认为等于无穷大。
在提供坐标时,支持以下格式:
Lat Lon as Properties
GET /_search
{
"sort" : [
{
"_geo_distance" : {
"pin.location" : {
"lat" : 40,
"lon" : -70
},
"order" : "asc",
"unit" : "km"
}
}
],
"query" : {
"term" : { "user" : "kimchy" }
}
}
Lat Lon as String
lat,lon中的格式。
GET /_search
{
"sort" : [
{
"_geo_distance" : {
"pin.location" : "40,-70",
"order" : "asc",
"unit" : "km"
}
}
],
"query" : {
"term" : { "user" : "kimchy" }
}
}
Geohash
GET /_search
{
"sort" : [
{
"_geo_distance" : {
"pin.location" : "drm3btev3e86",
"order" : "asc",
"unit" : "km"
}
}
],
"query" : {
"term" : { "user" : "kimchy" }
}
}
Lat Lon as Array
格式为[lon, lat],注意,这里的lon/lat顺序是为了符合GeoJSON。
GET /_search
{
"sort" : [
{
"_geo_distance" : {
"pin.location" : [-70, 40],
"order" : "asc",
"unit" : "km"
}
}
],
"query" : {
"term" : { "user" : "kimchy" }
}
}
Multiple reference points
例如,可以将多个地理点作为包含任何geo_point格式的数组传递
GET /_search
{
"sort" : [
{
"_geo_distance" : {
"pin.location" : [[-70, 40], [-71, 42]],
"order" : "asc",
"unit" : "km"
}
}
],
"query" : {
"term" : { "user" : "kimchy" }
}
}
等等。
文档的最终距离将是文档中包含的所有点到排序请求中给定的所有点的最小/最大/avg(通过模式定义)距离。
Script Based Sorting
允许基于自定义脚本排序,这里有一个例子:
GET /_search
{
"query" : {
"term" : { "user" : "kimchy" }
},
"sort" : {
"_script" : {
"type" : "number",
"script" : {
"lang": "painless",
"source": "doc['field_name'].value * params.factor",
"params" : {
"factor" : 1.1
}
},
"order" : "asc"
}
}
}
Track Scores
在字段上排序时,不计算分数。通过将track_scores设置为true,仍然可以计算和跟踪分数。
GET /_search
{
"track_scores": true,
"sort" : [
{ "post_date" : {"order" : "desc"} },
{ "name" : "desc" },
{ "age" : "desc" }
],
"query" : {
"term" : { "user" : "kimchy" }
}
}
Memory Considerations
排序时,相关的排序字段值将加载到内存中。 这意味着每个分片应该有足够的内存来包含它们。 对于基于字符串的类型,不应分析/标记化排序的字段。 对于数字类型,如果可能,建议将类型显式设置为较窄的类型(如short,integer和float)。
Source filtering
允许控制每次命中时返回_source字段的方式。
默认情况下,除非使用了stored_fields参数,或者禁用了_source字段,否则操作将返回_source字段的内容。
可以使用_source参数关闭_source检索:
若要禁用_source检索设置为false:
GET /_search
{
"_source": false,
"query" : {
"term" : { "user" : "kimchy" }
}
}
_source还接受一个或多个通配符模式来控制应该返回_source的哪些部分:
例如:
GET /_search
{
"_source": "obj.*",
"query" : {
"term" : { "user" : "kimchy" }
}
}
或
GET /_search
{
"_source": [ "obj1.*", "obj2.*" ],
"query" : {
"term" : { "user" : "kimchy" }
}
}
最后,对于完全控制,您可以指定include和exclude模式。如果include不是空的,那么_source中只提供与include中的模式之一匹配的字段,而不提供与exclude中的模式匹配的字段。如果include为空,则_source中提供所有字段,但与exclude中的模式匹配的字段除外。
GET /_search
{
"_source": {
"includes": [ "obj1.*", "obj2.*" ],
"excludes": [ "*.description" ]
},
"query" : {
"term" : { "user" : "kimchy" }
}
}