地理距離集約
geo_point
フィールドで動作するマルチバケット集約で、概念的には range 集約と非常に似ています。ユーザーは起点と一連の距離範囲バケットを定義できます。集約は各ドキュメント値の起点からの距離を評価し、距離がバケットの範囲内に収まる場合、そのバケットに属するかどうかを判断します(ドキュメントと起点の距離がバケットの距離範囲内にある場合、ドキュメントはそのバケットに属します)。
Python
resp = client.indices.create(
index="museums",
mappings={
"properties": {
"location": {
"type": "geo_point"
}
}
},
)
print(resp)
resp1 = client.bulk(
index="museums",
refresh=True,
operations=[
{
"index": {
"_id": 1
}
},
{
"location": "POINT (4.912350 52.374081)",
"name": "NEMO Science Museum"
},
{
"index": {
"_id": 2
}
},
{
"location": "POINT (4.901618 52.369219)",
"name": "Museum Het Rembrandthuis"
},
{
"index": {
"_id": 3
}
},
{
"location": "POINT (4.914722 52.371667)",
"name": "Nederlands Scheepvaartmuseum"
},
{
"index": {
"_id": 4
}
},
{
"location": "POINT (4.405200 51.222900)",
"name": "Letterenhuis"
},
{
"index": {
"_id": 5
}
},
{
"location": "POINT (2.336389 48.861111)",
"name": "Musée du Louvre"
},
{
"index": {
"_id": 6
}
},
{
"location": "POINT (2.327000 48.860000)",
"name": "Musée d'Orsay"
}
],
)
print(resp1)
resp2 = client.search(
index="museums",
size="0",
aggs={
"rings_around_amsterdam": {
"geo_distance": {
"field": "location",
"origin": "POINT (4.894 52.3760)",
"ranges": [
{
"to": 100000
},
{
"from": 100000,
"to": 300000
},
{
"from": 300000
}
]
}
}
},
)
print(resp2)
Ruby
response = client.indices.create(
index: 'museums',
body: {
mappings: {
properties: {
location: {
type: 'geo_point'
}
}
}
}
)
puts response
response = client.bulk(
index: 'museums',
refresh: true,
body: [
{
index: {
_id: 1
}
},
{
location: 'POINT (4.912350 52.374081)',
name: 'NEMO Science Museum'
},
{
index: {
_id: 2
}
},
{
location: 'POINT (4.901618 52.369219)',
name: 'Museum Het Rembrandthuis'
},
{
index: {
_id: 3
}
},
{
location: 'POINT (4.914722 52.371667)',
name: 'Nederlands Scheepvaartmuseum'
},
{
index: {
_id: 4
}
},
{
location: 'POINT (4.405200 51.222900)',
name: 'Letterenhuis'
},
{
index: {
_id: 5
}
},
{
location: 'POINT (2.336389 48.861111)',
name: 'Musée du Louvre'
},
{
index: {
_id: 6
}
},
{
location: 'POINT (2.327000 48.860000)',
name: "Musée d'Orsay"
}
]
)
puts response
response = client.search(
index: 'museums',
size: 0,
body: {
aggregations: {
rings_around_amsterdam: {
geo_distance: {
field: 'location',
origin: 'POINT (4.894 52.3760)',
ranges: [
{
to: 100_000
},
{
from: 100_000,
to: 300_000
},
{
from: 300_000
}
]
}
}
}
}
)
puts response
Js
const response = await client.indices.create({
index: "museums",
mappings: {
properties: {
location: {
type: "geo_point",
},
},
},
});
console.log(response);
const response1 = await client.bulk({
index: "museums",
refresh: "true",
operations: [
{
index: {
_id: 1,
},
},
{
location: "POINT (4.912350 52.374081)",
name: "NEMO Science Museum",
},
{
index: {
_id: 2,
},
},
{
location: "POINT (4.901618 52.369219)",
name: "Museum Het Rembrandthuis",
},
{
index: {
_id: 3,
},
},
{
location: "POINT (4.914722 52.371667)",
name: "Nederlands Scheepvaartmuseum",
},
{
index: {
_id: 4,
},
},
{
location: "POINT (4.405200 51.222900)",
name: "Letterenhuis",
},
{
index: {
_id: 5,
},
},
{
location: "POINT (2.336389 48.861111)",
name: "Musée du Louvre",
},
{
index: {
_id: 6,
},
},
{
location: "POINT (2.327000 48.860000)",
name: "Musée d'Orsay",
},
],
});
console.log(response1);
const response2 = await client.search({
index: "museums",
size: 0,
aggs: {
rings_around_amsterdam: {
geo_distance: {
field: "location",
origin: "POINT (4.894 52.3760)",
ranges: [
{
to: 100000,
},
{
from: 100000,
to: 300000,
},
{
from: 300000,
},
],
},
},
},
});
console.log(response2);
コンソール
PUT /museums
{
"mappings": {
"properties": {
"location": {
"type": "geo_point"
}
}
}
}
POST /museums/_bulk?refresh
{"index":{"_id":1}}
{"location": "POINT (4.912350 52.374081)", "name": "NEMO Science Museum"}
{"index":{"_id":2}}
{"location": "POINT (4.901618 52.369219)", "name": "Museum Het Rembrandthuis"}
{"index":{"_id":3}}
{"location": "POINT (4.914722 52.371667)", "name": "Nederlands Scheepvaartmuseum"}
{"index":{"_id":4}}
{"location": "POINT (4.405200 51.222900)", "name": "Letterenhuis"}
{"index":{"_id":5}}
{"location": "POINT (2.336389 48.861111)", "name": "Musée du Louvre"}
{"index":{"_id":6}}
{"location": "POINT (2.327000 48.860000)", "name": "Musée d'Orsay"}
POST /museums/_search?size=0
{
"aggs": {
"rings_around_amsterdam": {
"geo_distance": {
"field": "location",
"origin": "POINT (4.894 52.3760)",
"ranges": [
{ "to": 100000 },
{ "from": 100000, "to": 300000 },
{ "from": 300000 }
]
}
}
}
}
コンソール-結果
{
...
"aggregations": {
"rings_around_amsterdam": {
"buckets": [
{
"key": "*-100000.0",
"from": 0.0,
"to": 100000.0,
"doc_count": 3
},
{
"key": "100000.0-300000.0",
"from": 100000.0,
"to": 300000.0,
"doc_count": 1
},
{
"key": "300000.0-*",
"from": 300000.0,
"doc_count": 2
}
]
}
}
}
指定されたフィールドは geo_point
型でなければなりません(これはマッピングで明示的に設定することができます)。また、geo_point
フィールドの配列を保持することもでき、その場合、すべてが集約中に考慮されます。起点は geo_point
型 によってサポートされるすべての形式を受け入れることができます:
- オブジェクト形式:
{ "lat" : 52.3760, "lon" : 4.894 }
- これはlat
とlon
の値について最も明示的で安全な形式です - 文字列形式:
"52.3760, 4.894"
- 最初の数値がlat
で、2番目がlon
です - 配列形式:
[4.894, 52.3760]
- これは GeoJSON 標準に基づいており、最初の数値がlon
で、2番目がlat
です
デフォルトでは、距離単位は m
(メートル) ですが、次のものも受け入れられます: mi
(マイル)、in
(インチ)、yd
(ヤード)、km
(キロメートル)、cm
(センチメートル)、mm
(ミリメートル)。
Python
resp = client.search(
index="museums",
size="0",
aggs={
"rings": {
"geo_distance": {
"field": "location",
"origin": "POINT (4.894 52.3760)",
"unit": "km",
"ranges": [
{
"to": 100
},
{
"from": 100,
"to": 300
},
{
"from": 300
}
]
}
}
},
)
print(resp)
Ruby
response = client.search(
index: 'museums',
size: 0,
body: {
aggregations: {
rings: {
geo_distance: {
field: 'location',
origin: 'POINT (4.894 52.3760)',
unit: 'km',
ranges: [
{
to: 100
},
{
from: 100,
to: 300
},
{
from: 300
}
]
}
}
}
}
)
puts response
Js
const response = await client.search({
index: "museums",
size: 0,
aggs: {
rings: {
geo_distance: {
field: "location",
origin: "POINT (4.894 52.3760)",
unit: "km",
ranges: [
{
to: 100,
},
{
from: 100,
to: 300,
},
{
from: 300,
},
],
},
},
},
});
console.log(response);
コンソール
POST /museums/_search?size=0
{
"aggs": {
"rings": {
"geo_distance": {
"field": "location",
"origin": "POINT (4.894 52.3760)",
"unit": "km",
"ranges": [
{ "to": 100 },
{ "from": 100, "to": 300 },
{ "from": 300 }
]
}
}
}
}
距離はキロメートルで計算されます |
距離計算モードは2つあります: arc
(デフォルト) と plane
。arc
計算は最も正確です。plane
は最も速いですが、最も正確ではありません。検索コンテキストが「狭い」場合(約5km)には plane
を使用することを検討してください。plane
は非常に大きな地域(例: 大陸を越える検索)での検索に対して高い誤差範囲を返します。距離計算タイプは distance_type
パラメータを使用して設定できます:
Python
resp = client.search(
index="museums",
size="0",
aggs={
"rings": {
"geo_distance": {
"field": "location",
"origin": "POINT (4.894 52.3760)",
"unit": "km",
"distance_type": "plane",
"ranges": [
{
"to": 100
},
{
"from": 100,
"to": 300
},
{
"from": 300
}
]
}
}
},
)
print(resp)
Ruby
response = client.search(
index: 'museums',
size: 0,
body: {
aggregations: {
rings: {
geo_distance: {
field: 'location',
origin: 'POINT (4.894 52.3760)',
unit: 'km',
distance_type: 'plane',
ranges: [
{
to: 100
},
{
from: 100,
to: 300
},
{
from: 300
}
]
}
}
}
}
)
puts response
Js
const response = await client.search({
index: "museums",
size: 0,
aggs: {
rings: {
geo_distance: {
field: "location",
origin: "POINT (4.894 52.3760)",
unit: "km",
distance_type: "plane",
ranges: [
{
to: 100,
},
{
from: 100,
to: 300,
},
{
from: 300,
},
],
},
},
},
});
console.log(response);
コンソール
POST /museums/_search?size=0
{
"aggs": {
"rings": {
"geo_distance": {
"field": "location",
"origin": "POINT (4.894 52.3760)",
"unit": "km",
"distance_type": "plane",
"ranges": [
{ "to": 100 },
{ "from": 100, "to": 300 },
{ "from": 300 }
]
}
}
}
}
キー付きレスポンス
keyed
フラグを true
に設定すると、各バケットに一意の文字列キーが関連付けられ、範囲が配列ではなくハッシュとして返されます:
Python
resp = client.search(
index="museums",
size="0",
aggs={
"rings_around_amsterdam": {
"geo_distance": {
"field": "location",
"origin": "POINT (4.894 52.3760)",
"ranges": [
{
"to": 100000
},
{
"from": 100000,
"to": 300000
},
{
"from": 300000
}
],
"keyed": True
}
}
},
)
print(resp)
Ruby
response = client.search(
index: 'museums',
size: 0,
body: {
aggregations: {
rings_around_amsterdam: {
geo_distance: {
field: 'location',
origin: 'POINT (4.894 52.3760)',
ranges: [
{
to: 100_000
},
{
from: 100_000,
to: 300_000
},
{
from: 300_000
}
],
keyed: true
}
}
}
}
)
puts response
Js
const response = await client.search({
index: "museums",
size: 0,
aggs: {
rings_around_amsterdam: {
geo_distance: {
field: "location",
origin: "POINT (4.894 52.3760)",
ranges: [
{
to: 100000,
},
{
from: 100000,
to: 300000,
},
{
from: 300000,
},
],
keyed: true,
},
},
},
});
console.log(response);
コンソール
POST /museums/_search?size=0
{
"aggs": {
"rings_around_amsterdam": {
"geo_distance": {
"field": "location",
"origin": "POINT (4.894 52.3760)",
"ranges": [
{ "to": 100000 },
{ "from": 100000, "to": 300000 },
{ "from": 300000 }
],
"keyed": true
}
}
}
}
コンソール-結果
{
...
"aggregations": {
"rings_around_amsterdam": {
"buckets": {
"*-100000.0": {
"from": 0.0,
"to": 100000.0,
"doc_count": 3
},
"100000.0-300000.0": {
"from": 100000.0,
"to": 300000.0,
"doc_count": 1
},
"300000.0-*": {
"from": 300000.0,
"doc_count": 2
}
}
}
}
}
各範囲のキーをカスタマイズすることも可能です:
Python
resp = client.search(
index="museums",
size="0",
aggs={
"rings_around_amsterdam": {
"geo_distance": {
"field": "location",
"origin": "POINT (4.894 52.3760)",
"ranges": [
{
"to": 100000,
"key": "first_ring"
},
{
"from": 100000,
"to": 300000,
"key": "second_ring"
},
{
"from": 300000,
"key": "third_ring"
}
],
"keyed": True
}
}
},
)
print(resp)
Ruby
response = client.search(
index: 'museums',
size: 0,
body: {
aggregations: {
rings_around_amsterdam: {
geo_distance: {
field: 'location',
origin: 'POINT (4.894 52.3760)',
ranges: [
{
to: 100_000,
key: 'first_ring'
},
{
from: 100_000,
to: 300_000,
key: 'second_ring'
},
{
from: 300_000,
key: 'third_ring'
}
],
keyed: true
}
}
}
}
)
puts response
Js
const response = await client.search({
index: "museums",
size: 0,
aggs: {
rings_around_amsterdam: {
geo_distance: {
field: "location",
origin: "POINT (4.894 52.3760)",
ranges: [
{
to: 100000,
key: "first_ring",
},
{
from: 100000,
to: 300000,
key: "second_ring",
},
{
from: 300000,
key: "third_ring",
},
],
keyed: true,
},
},
},
});
console.log(response);
コンソール
POST /museums/_search?size=0
{
"aggs": {
"rings_around_amsterdam": {
"geo_distance": {
"field": "location",
"origin": "POINT (4.894 52.3760)",
"ranges": [
{ "to": 100000, "key": "first_ring" },
{ "from": 100000, "to": 300000, "key": "second_ring" },
{ "from": 300000, "key": "third_ring" }
],
"keyed": true
}
}
}
}
コンソール-結果
{
...
"aggregations": {
"rings_around_amsterdam": {
"buckets": {
"first_ring": {
"from": 0.0,
"to": 100000.0,
"doc_count": 3
},
"second_ring": {
"from": 100000.0,
"to": 300000.0,
"doc_count": 1
},
"third_ring": {
"from": 300000.0,
"doc_count": 2
}
}
}
}
}