地理边界框查询

编辑

匹配与边界框相交的 geo_pointgeo_shape 值。

示例

编辑

假设索引了以下文档

resp = client.indices.create(
    index="my_locations",
    mappings={
        "properties": {
            "pin": {
                "properties": {
                    "location": {
                        "type": "geo_point"
                    }
                }
            }
        }
    },
)
print(resp)

resp1 = client.index(
    index="my_locations",
    id="1",
    document={
        "pin": {
            "location": {
                "lat": 40.12,
                "lon": -71.34
            }
        }
    },
)
print(resp1)

resp2 = client.indices.create(
    index="my_geoshapes",
    mappings={
        "properties": {
            "pin": {
                "properties": {
                    "location": {
                        "type": "geo_shape"
                    }
                }
            }
        }
    },
)
print(resp2)

resp3 = client.index(
    index="my_geoshapes",
    id="1",
    document={
        "pin": {
            "location": {
                "type": "polygon",
                "coordinates": [
                    [
                        [
                            13,
                            51.5
                        ],
                        [
                            15,
                            51.5
                        ],
                        [
                            15,
                            54
                        ],
                        [
                            13,
                            54
                        ],
                        [
                            13,
                            51.5
                        ]
                    ]
                ]
            }
        }
    },
)
print(resp3)
response = client.indices.create(
  index: 'my_locations',
  body: {
    mappings: {
      properties: {
        pin: {
          properties: {
            location: {
              type: 'geo_point'
            }
          }
        }
      }
    }
  }
)
puts response

response = client.index(
  index: 'my_locations',
  id: 1,
  body: {
    pin: {
      location: {
        lat: 40.12,
        lon: -71.34
      }
    }
  }
)
puts response

response = client.indices.create(
  index: 'my_geoshapes',
  body: {
    mappings: {
      properties: {
        pin: {
          properties: {
            location: {
              type: 'geo_shape'
            }
          }
        }
      }
    }
  }
)
puts response

response = client.index(
  index: 'my_geoshapes',
  id: 1,
  body: {
    pin: {
      location: {
        type: 'polygon',
        coordinates: [
          [
            [
              13,
              51.5
            ],
            [
              15,
              51.5
            ],
            [
              15,
              54
            ],
            [
              13,
              54
            ],
            [
              13,
              51.5
            ]
          ]
        ]
      }
    }
  }
)
puts response
const response = await client.indices.create({
  index: "my_locations",
  mappings: {
    properties: {
      pin: {
        properties: {
          location: {
            type: "geo_point",
          },
        },
      },
    },
  },
});
console.log(response);

const response1 = await client.index({
  index: "my_locations",
  id: 1,
  document: {
    pin: {
      location: {
        lat: 40.12,
        lon: -71.34,
      },
    },
  },
});
console.log(response1);

const response2 = await client.indices.create({
  index: "my_geoshapes",
  mappings: {
    properties: {
      pin: {
        properties: {
          location: {
            type: "geo_shape",
          },
        },
      },
    },
  },
});
console.log(response2);

const response3 = await client.index({
  index: "my_geoshapes",
  id: 1,
  document: {
    pin: {
      location: {
        type: "polygon",
        coordinates: [
          [
            [13, 51.5],
            [15, 51.5],
            [15, 54],
            [13, 54],
            [13, 51.5],
          ],
        ],
      },
    },
  },
});
console.log(response3);
PUT /my_locations
{
  "mappings": {
    "properties": {
      "pin": {
        "properties": {
          "location": {
            "type": "geo_point"
          }
        }
      }
    }
  }
}

PUT /my_locations/_doc/1
{
  "pin": {
    "location": {
      "lat": 40.12,
      "lon": -71.34
    }
  }
}

PUT /my_geoshapes
{
  "mappings": {
    "properties": {
      "pin": {
        "properties": {
          "location": {
            "type": "geo_shape"
          }
        }
      }
    }
  }
}

PUT /my_geoshapes/_doc/1
{
  "pin": {
    "location": {
      "type" : "polygon",
      "coordinates" : [[[13.0 ,51.5], [15.0, 51.5], [15.0, 54.0], [13.0, 54.0], [13.0 ,51.5]]]
    }
  }
}

使用 geo_bounding_box 过滤器来匹配与边界框相交的 geo_point 值。要定义框,请为两个对角提供地理点值。

resp = client.search(
    index="my_locations",
    query={
        "bool": {
            "must": {
                "match_all": {}
            },
            "filter": {
                "geo_bounding_box": {
                    "pin.location": {
                        "top_left": {
                            "lat": 40.73,
                            "lon": -74.1
                        },
                        "bottom_right": {
                            "lat": 40.01,
                            "lon": -71.12
                        }
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'my_locations',
  body: {
    query: {
      bool: {
        must: {
          match_all: {}
        },
        filter: {
          geo_bounding_box: {
            'pin.location' => {
              top_left: {
                lat: 40.73,
                lon: -74.1
              },
              bottom_right: {
                lat: 40.01,
                lon: -71.12
              }
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "my_locations",
  query: {
    bool: {
      must: {
        match_all: {},
      },
      filter: {
        geo_bounding_box: {
          "pin.location": {
            top_left: {
              lat: 40.73,
              lon: -74.1,
            },
            bottom_right: {
              lat: 40.01,
              lon: -71.12,
            },
          },
        },
      },
    },
  },
});
console.log(response);
GET my_locations/_search
{
  "query": {
    "bool": {
      "must": {
        "match_all": {}
      },
      "filter": {
        "geo_bounding_box": {
          "pin.location": {
            "top_left": {
              "lat": 40.73,
              "lon": -74.1
            },
            "bottom_right": {
              "lat": 40.01,
              "lon": -71.12
            }
          }
        }
      }
    }
  }
}

使用相同的过滤器来匹配与边界框相交的 geo_shape 值。

resp = client.search(
    index="my_geoshapes",
    query={
        "bool": {
            "must": {
                "match_all": {}
            },
            "filter": {
                "geo_bounding_box": {
                    "pin.location": {
                        "top_left": {
                            "lat": 40.73,
                            "lon": -74.1
                        },
                        "bottom_right": {
                            "lat": 40.01,
                            "lon": -71.12
                        }
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'my_geoshapes',
  body: {
    query: {
      bool: {
        must: {
          match_all: {}
        },
        filter: {
          geo_bounding_box: {
            'pin.location' => {
              top_left: {
                lat: 40.73,
                lon: -74.1
              },
              bottom_right: {
                lat: 40.01,
                lon: -71.12
              }
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "my_geoshapes",
  query: {
    bool: {
      must: {
        match_all: {},
      },
      filter: {
        geo_bounding_box: {
          "pin.location": {
            top_left: {
              lat: 40.73,
              lon: -74.1,
            },
            bottom_right: {
              lat: 40.01,
              lon: -71.12,
            },
          },
        },
      },
    },
  },
});
console.log(response);
GET my_geoshapes/_search
{
  "query": {
    "bool": {
      "must": {
        "match_all": {}
      },
      "filter": {
        "geo_bounding_box": {
          "pin.location": {
            "top_left": {
              "lat": 40.73,
              "lon": -74.1
            },
            "bottom_right": {
              "lat": 40.01,
              "lon": -71.12
            }
          }
        }
      }
    }
  }
}

要匹配 geo_pointgeo_shape 值,请搜索两个索引

resp = client.search(
    index="my_locations,my_geoshapes",
    query={
        "bool": {
            "must": {
                "match_all": {}
            },
            "filter": {
                "geo_bounding_box": {
                    "pin.location": {
                        "top_left": {
                            "lat": 40.73,
                            "lon": -74.1
                        },
                        "bottom_right": {
                            "lat": 40.01,
                            "lon": -71.12
                        }
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'my_locations,my_geoshapes',
  body: {
    query: {
      bool: {
        must: {
          match_all: {}
        },
        filter: {
          geo_bounding_box: {
            'pin.location' => {
              top_left: {
                lat: 40.73,
                lon: -74.1
              },
              bottom_right: {
                lat: 40.01,
                lon: -71.12
              }
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "my_locations,my_geoshapes",
  query: {
    bool: {
      must: {
        match_all: {},
      },
      filter: {
        geo_bounding_box: {
          "pin.location": {
            top_left: {
              lat: 40.73,
              lon: -74.1,
            },
            bottom_right: {
              lat: 40.01,
              lon: -71.12,
            },
          },
        },
      },
    },
  },
});
console.log(response);
GET my_locations,my_geoshapes/_search
{
  "query": {
    "bool": {
      "must": {
        "match_all": {}
      },
      "filter": {
        "geo_bounding_box": {
          "pin.location": {
            "top_left": {
              "lat": 40.73,
              "lon": -74.1
            },
            "bottom_right": {
              "lat": 40.01,
              "lon": -71.12
            }
          }
        }
      }
    }
  }
}

查询选项

编辑
选项 描述

_name

用于标识过滤器的可选名称字段

validation_method

设置为 IGNORE_MALFORMED 以接受具有无效纬度或经度的地理点,设置为 COERCE 以尝试推断正确的纬度或经度。(默认为 STRICT)。

接受的格式

编辑

geo_point 类型可以接受地理点的不同表示方式非常相似,该过滤器也可以接受这些表示方式。

纬度/经度作为属性
编辑
resp = client.search(
    index="my_locations",
    query={
        "bool": {
            "must": {
                "match_all": {}
            },
            "filter": {
                "geo_bounding_box": {
                    "pin.location": {
                        "top_left": {
                            "lat": 40.73,
                            "lon": -74.1
                        },
                        "bottom_right": {
                            "lat": 40.01,
                            "lon": -71.12
                        }
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'my_locations',
  body: {
    query: {
      bool: {
        must: {
          match_all: {}
        },
        filter: {
          geo_bounding_box: {
            'pin.location' => {
              top_left: {
                lat: 40.73,
                lon: -74.1
              },
              bottom_right: {
                lat: 40.01,
                lon: -71.12
              }
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "my_locations",
  query: {
    bool: {
      must: {
        match_all: {},
      },
      filter: {
        geo_bounding_box: {
          "pin.location": {
            top_left: {
              lat: 40.73,
              lon: -74.1,
            },
            bottom_right: {
              lat: 40.01,
              lon: -71.12,
            },
          },
        },
      },
    },
  },
});
console.log(response);
GET my_locations/_search
{
  "query": {
    "bool": {
      "must": {
        "match_all": {}
      },
      "filter": {
        "geo_bounding_box": {
          "pin.location": {
            "top_left": {
              "lat": 40.73,
              "lon": -74.1
            },
            "bottom_right": {
              "lat": 40.01,
              "lon": -71.12
            }
          }
        }
      }
    }
  }
}
纬度/经度作为数组
编辑

格式为 [lon, lat],请注意,这里的经度/纬度顺序是为了符合 GeoJSON

resp = client.search(
    index="my_locations",
    query={
        "bool": {
            "must": {
                "match_all": {}
            },
            "filter": {
                "geo_bounding_box": {
                    "pin.location": {
                        "top_left": [
                            -74.1,
                            40.73
                        ],
                        "bottom_right": [
                            -71.12,
                            40.01
                        ]
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'my_locations',
  body: {
    query: {
      bool: {
        must: {
          match_all: {}
        },
        filter: {
          geo_bounding_box: {
            'pin.location' => {
              top_left: [
                -74.1,
                40.73
              ],
              bottom_right: [
                -71.12,
                40.01
              ]
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "my_locations",
  query: {
    bool: {
      must: {
        match_all: {},
      },
      filter: {
        geo_bounding_box: {
          "pin.location": {
            top_left: [-74.1, 40.73],
            bottom_right: [-71.12, 40.01],
          },
        },
      },
    },
  },
});
console.log(response);
GET my_locations/_search
{
  "query": {
    "bool": {
      "must": {
        "match_all": {}
      },
      "filter": {
        "geo_bounding_box": {
          "pin.location": {
            "top_left": [ -74.1, 40.73 ],
            "bottom_right": [ -71.12, 40.01 ]
          }
        }
      }
    }
  }
}
纬度/经度作为字符串
编辑

格式为 lat,lon

resp = client.search(
    index="my_locations",
    query={
        "bool": {
            "must": {
                "match_all": {}
            },
            "filter": {
                "geo_bounding_box": {
                    "pin.location": {
                        "top_left": "POINT (-74.1 40.73)",
                        "bottom_right": "POINT (-71.12 40.01)"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'my_locations',
  body: {
    query: {
      bool: {
        must: {
          match_all: {}
        },
        filter: {
          geo_bounding_box: {
            'pin.location' => {
              top_left: 'POINT (-74.1 40.73)',
              bottom_right: 'POINT (-71.12 40.01)'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "my_locations",
  query: {
    bool: {
      must: {
        match_all: {},
      },
      filter: {
        geo_bounding_box: {
          "pin.location": {
            top_left: "POINT (-74.1 40.73)",
            bottom_right: "POINT (-71.12 40.01)",
          },
        },
      },
    },
  },
});
console.log(response);
GET my_locations/_search
{
  "query": {
    "bool": {
      "must": {
        "match_all": {}
      },
      "filter": {
        "geo_bounding_box": {
          "pin.location": {
            "top_left": "POINT (-74.1 40.73)",
            "bottom_right": "POINT (-71.12 40.01)"
          }
        }
      }
    }
  }
}
边界框作为众所周知的文本 (WKT)
编辑
resp = client.search(
    index="my_locations",
    query={
        "bool": {
            "must": {
                "match_all": {}
            },
            "filter": {
                "geo_bounding_box": {
                    "pin.location": {
                        "wkt": "BBOX (-74.1, -71.12, 40.73, 40.01)"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'my_locations',
  body: {
    query: {
      bool: {
        must: {
          match_all: {}
        },
        filter: {
          geo_bounding_box: {
            'pin.location' => {
              wkt: 'BBOX (-74.1, -71.12, 40.73, 40.01)'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "my_locations",
  query: {
    bool: {
      must: {
        match_all: {},
      },
      filter: {
        geo_bounding_box: {
          "pin.location": {
            wkt: "BBOX (-74.1, -71.12, 40.73, 40.01)",
          },
        },
      },
    },
  },
});
console.log(response);
GET my_locations/_search
{
  "query": {
    "bool": {
      "must": {
        "match_all": {}
      },
      "filter": {
        "geo_bounding_box": {
          "pin.location": {
            "wkt": "BBOX (-74.1, -71.12, 40.73, 40.01)"
          }
        }
      }
    }
  }
}
地理哈希
编辑
resp = client.search(
    index="my_locations",
    query={
        "bool": {
            "must": {
                "match_all": {}
            },
            "filter": {
                "geo_bounding_box": {
                    "pin.location": {
                        "top_left": "dr5r9ydj2y73",
                        "bottom_right": "drj7teegpus6"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'my_locations',
  body: {
    query: {
      bool: {
        must: {
          match_all: {}
        },
        filter: {
          geo_bounding_box: {
            'pin.location' => {
              top_left: 'dr5r9ydj2y73',
              bottom_right: 'drj7teegpus6'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "my_locations",
  query: {
    bool: {
      must: {
        match_all: {},
      },
      filter: {
        geo_bounding_box: {
          "pin.location": {
            top_left: "dr5r9ydj2y73",
            bottom_right: "drj7teegpus6",
          },
        },
      },
    },
  },
});
console.log(response);
GET my_locations/_search
{
  "query": {
    "bool": {
      "must": {
        "match_all": {}
      },
      "filter": {
        "geo_bounding_box": {
          "pin.location": {
            "top_left": "dr5r9ydj2y73",
            "bottom_right": "drj7teegpus6"
          }
        }
      }
    }
  }
}

当使用地理哈希指定边界框的边缘时,这些地理哈希被视为矩形。边界框的定义方式是,其左上角对应于 top_left 参数中指定的地理哈希的左上角,而其右下角定义为 bottom_right 参数中指定的地理哈希的右下角。

为了指定一个与地理哈希的整个区域匹配的边界框,可以在 top_leftbottom_right 参数中都指定该地理哈希。

resp = client.search(
    index="my_locations",
    query={
        "geo_bounding_box": {
            "pin.location": {
                "top_left": "dr",
                "bottom_right": "dr"
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'my_locations',
  body: {
    query: {
      geo_bounding_box: {
        'pin.location' => {
          top_left: 'dr',
          bottom_right: 'dr'
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "my_locations",
  query: {
    geo_bounding_box: {
      "pin.location": {
        top_left: "dr",
        bottom_right: "dr",
      },
    },
  },
});
console.log(response);
GET my_locations/_search
{
  "query": {
    "geo_bounding_box": {
      "pin.location": {
        "top_left": "dr",
        "bottom_right": "dr"
      }
    }
  }
}

在此示例中,地理哈希 dr 将生成一个边界框查询,其左上角为 45.0,-78.75,右下角为 39.375,-67.5

顶点

编辑

边界框的顶点可以通过 top_leftbottom_righttop_rightbottom_left 参数进行设置。除了成对设置值外,还可以使用简单的名称 topleftbottomright 分别设置值。

resp = client.search(
    index="my_locations",
    query={
        "bool": {
            "must": {
                "match_all": {}
            },
            "filter": {
                "geo_bounding_box": {
                    "pin.location": {
                        "top": 40.73,
                        "left": -74.1,
                        "bottom": 40.01,
                        "right": -71.12
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'my_locations',
  body: {
    query: {
      bool: {
        must: {
          match_all: {}
        },
        filter: {
          geo_bounding_box: {
            'pin.location' => {
              top: 40.73,
              left: -74.1,
              bottom: 40.01,
              right: -71.12
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "my_locations",
  query: {
    bool: {
      must: {
        match_all: {},
      },
      filter: {
        geo_bounding_box: {
          "pin.location": {
            top: 40.73,
            left: -74.1,
            bottom: 40.01,
            right: -71.12,
          },
        },
      },
    },
  },
});
console.log(response);
GET my_locations/_search
{
  "query": {
    "bool": {
      "must": {
        "match_all": {}
      },
      "filter": {
        "geo_bounding_box": {
          "pin.location": {
            "top": 40.73,
            "left": -74.1,
            "bottom": 40.01,
            "right": -71.12
          }
        }
      }
    }
  }
}

每个文档的多个位置

编辑

该过滤器可以处理每个文档的多个位置/点。一旦单个位置/点与过滤器匹配,该文档将包含在过滤器中。

忽略未映射

编辑

当设置为 true 时, ignore_unmapped 选项将忽略未映射的字段,并且不会匹配此查询的任何文档。在查询可能具有不同映射的多个索引时,这会很有用。当设置为 false(默认值)时,如果字段未映射,则查询将引发异常。

关于精度的注意事项

编辑

地理点具有有限的精度,并且在索引时始终向下舍入。在查询期间,边界框的上限向下舍入,而下限向上舍入。因此,由于舍入误差,沿着下限(边界框的底部和左边缘)的点可能无法进入边界框。同时,即使位于边缘之外,查询也可能会选择沿着上限(顶部和右边缘)的点。纬度上的舍入误差应小于 4.20e-8 度,经度上的舍入误差应小于 8.39e-8 度,即使在赤道,也转化为小于 1 厘米的误差。

由于舍入,地理形状也具有有限的精度。沿着边界框的底部和左边缘的地理形状边缘可能与 geo_bounding_box 查询不匹配。稍微超出框的顶部和右边缘的地理形状边缘仍然可能匹配查询。