Spec-Zone.ru › Elasticsearch 8
›Elasticsearch Guide [8.17] ›Query DSL ›Geo запросы

Запрос по гео-прямоугольнику

Совпадает с geo_point и geo_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_point, так и значений geo_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 (Well-known text)
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)"
          }
        }
      }
    }
  }
}
Geohash
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"
          }
        }
      }
    }
  }
}

Когда geohash используется для указания границ прямоугольника, geohashes обрабатываются как прямоугольники. Прямоугольник определяется таким образом, что его верхний левый угол соответствует верхнему левому углу geohash, указанному в параметре top_left, а его нижний правый угол определяется как нижний правый угол geohash, указанный в параметре bottom_right.

Чтобы указать прямоугольник, который соответствовал бы всей области geohash, geohash можно указать в параметрах top_left и bottom_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"
      }
    }
  }
}

В этом примере geohash dr приведет к запросу прямоугольника с верхним левым углом в 45.0,-78.75 и нижним правым углом в 39.375,-67.5.

Вершины

Вершины прямоугольника могут быть заданы параметрами top_left и bottom_right или параметрами top_right и bottom_left. Вместо задания значений попарно, можно использовать простые имена top, left, bottom и right для задания значений по отдельности.

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. Грани геоформ, находящиеся немного за пределами верхних и правых граней прямоугольника, все равно могут соответствовать запросу.

© 2023-2025 Elasticsearch
As of September 2024, Elasticsearch is available under a choice of three licenses: the Server Side Public License (SSPL), the Elastic License, or the AGPLv3 (OSI approved).
Elasticsearch and the Elasticsearch logo are trademarks of Elasticsearch B.V., registered in the U.S. and in other countries.
https://www.elastic.co/guide/en/elasticsearch/reference/8.17/query-dsl-geo-bounding-box-query.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API