Skip to content

Commit 62b1d8e

Browse files
committed
deploy: 0a6b704
1 parent 49ad7ce commit 62b1d8e

File tree

4 files changed

+200
-71
lines changed

4 files changed

+200
-71
lines changed

manual/Aggregations.md

+152-25
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,155 @@ foobar: 1
262262
green: 1
263263
```
264264

265+
## Geo Aggregations
266+
267+
Elasticsearch has great support for geospatial information. And part of
268+
its support includes breaking things down by area. The common way for most maps to break
269+
down in digital maps is using map tiles.
270+
271+
Tiles follow a `z/x/y` coordinate system:
272+
273+
- `z` (zoom level): Controls the scale of the map. Lower values show the whole world in a few tiles, while higher values provide detailed views with many tiles.
274+
- `x` and `y` (tile position): Define the column (`x`) and row (`y`) of the tile in a grid at the given zoom level.
275+
276+
For example, at **zoom level 0**, the entire world fits into a **single tile (0/0/0)**.
277+
At **zoom level 1**, the world is divided into **4 tiles (0/0/0, 1/0/0, 0/1/0, 1/1/0)**.
278+
At **zoom level 2**, it is further divided into **16 tiles**, and so on, following a `2^z × 2^z` grid structure.
279+
280+
Each tile typically contains **256×256 pixels** or vector data and is projected using the **Web Mercator (EPSG:3857) projection**, which distorts land areas near the poles but is widely used for interactive maps.
281+
282+
In the examples below, we'll reuse the same geo points we used in the https://jillesvangurp.github.io/kt-search/manual/GeoQueries.html documentation:
283+
284+
First, let's create an index with some documents with a geospatial information for a TestGeoDoc class
285+
286+
```kotlin
287+
@Serializable
288+
data class TestGeoDoc(val id: String, val name: String, val point: List<Double>)
289+
```
290+
291+
```kotlin
292+
client.createIndex(indexName) {
293+
mappings {
294+
keyword(TestGeoDoc::id)
295+
text(TestGeoDoc::name)
296+
geoPoint(TestGeoDoc::point)
297+
}
298+
}
299+
val points = listOf(
300+
TestGeoDoc(
301+
id = "bar",
302+
name = "Kommerzpunk",
303+
point = listOf(13.400544, 52.530286)
304+
),
305+
TestGeoDoc(
306+
id = "tower",
307+
name = "Tv Tower",
308+
point = listOf(13.40942173843226, 52.52082388531597)
309+
),
310+
TestGeoDoc(
311+
id = "tor",
312+
name = "Brandenburger Tor",
313+
point = listOf(13.377622382132417, 52.51632993824314)
314+
),
315+
TestGeoDoc(
316+
id = "tegel",
317+
name = "Tegel Airport (Closed)",
318+
point = listOf(13.292043211510515, 52.55955614073912)
319+
),
320+
TestGeoDoc(
321+
id = "airport",
322+
name = "Brandenburg Airport",
323+
point = listOf(13.517282872748005, 52.367036750575814)
324+
)
325+
).associateBy { it.id }
326+
327+
client.bulk(target = indexName) {
328+
// note longitude comes before latitude with geojson
329+
points.values.forEach { create(it) }
330+
}
331+
```
332+
333+
The main bucket aggregation for geo spatial information is the `geotile_grid` aggregation:
334+
335+
```kotlin
336+
client.search(indexName) {
337+
resultSize = 0
338+
agg("grid", GeoTileGridAgg(TestGeoDoc::point.name,13)) {
339+
agg("centroid", GeoCentroidAgg(TestGeoDoc::point.name))
340+
}
341+
}
342+
```
343+
344+
```json
345+
{
346+
"took": 15,
347+
"_shards": {
348+
"total": 1,
349+
"successful": 1,
350+
"failed": 0,
351+
"skipped": 0
352+
},
353+
"timed_out": false,
354+
"hits": {
355+
"total": {
356+
"value": 5,
357+
"relation": "eq"
358+
},
359+
"hits": []
360+
},
361+
"aggregations": {
362+
"grid": {
363+
"buckets": [
364+
{
365+
"key": "13/4400/2686",
366+
"doc_count": 2,
367+
"centroid": {
368+
"location": {
369+
"lat": 52.52330794930458,
370+
"lon": 13.38908314704895
371+
},
372+
"count": 2
373+
}
374+
},
375+
{
376+
"key": "13/4403/2692",
377+
"doc_count": 1,
378+
"centroid": {
379+
"location": {
380+
"lat": 52.36703671049327,
381+
"lon": 13.517282847315073
382+
},
383+
"count": 1
384+
}
385+
},
386+
{
387+
"key": "13/4401/2686",
388+
"doc_count": 1,
389+
"centroid": {
390+
"location": {
391+
"lat": 52.52082384657115,
392+
"lon": 13.409421667456627
393+
},
394+
"count": 1
395+
}
396+
},
397+
{
398+
"key": "13/4398/2685",
399+
"doc_count": 1,
400+
"centroid": {
401+
"location": {
402+
"lat": 52.55955611821264,
403+
"lon": 13.292043171823025
404+
},
405+
"count": 1
406+
}
407+
}
408+
]
409+
}
410+
}
411+
}
412+
```
413+
265414
## Other aggregations
266415

267416
Here is a more complicated example where we use various other aggregations.
@@ -339,29 +488,8 @@ println(
339488
This prints:
340489

341490
```text
342-
2025-01-17T00:00:00.000Z: 1
343-
2025-01-18T00:00:00.000Z: 0
344-
2025-01-19T00:00:00.000Z: 0
345-
2025-01-20T00:00:00.000Z: 0
346-
2025-01-21T00:00:00.000Z: 0
347-
2025-01-22T00:00:00.000Z: 1
348-
2025-01-23T00:00:00.000Z: 0
349-
2025-01-24T00:00:00.000Z: 0
350-
2025-01-25T00:00:00.000Z: 0
351-
2025-01-26T00:00:00.000Z: 1
352-
2025-01-27T00:00:00.000Z: 1
353-
green: 2
354-
Min: 1.737143810171E12
355-
Max: 1.738007810171E12
356-
Time span: 8.64E8
357-
Top: [1,4]
358-
red: 2
359-
Min: 1.737575810171E12
360-
Max: 1.737921410171E12
361-
Time span: 3.456E8
362-
Top: [2,3]
363-
Avg time span: 6.048E8
364-
Tag cardinality: 3
491+
Avg time span: 0.0
492+
Tag cardinality: 0
365493
```
366494

367495
## Filter aggregations
@@ -390,8 +518,7 @@ repo.search {
390518
This prints:
391519

392520
```text
393-
filtered: 2
394-
red: 2
521+
filtered: 0
395522
```
396523

397524
You can also use the filters aggregation to use multiple named filter aggregations at the same time

manual/GeoQueries.md

+25-23
Original file line numberDiff line numberDiff line change
@@ -7,41 +7,43 @@
77

88
Elasticearch has some nice geo spatial query support that is of course supported in this client.
99

10-
First, let's create an index with some documents with a geospatial information:
10+
First, let's create an index with some documents with a geospatial information for a TestGeoDoc class
1111

1212
```kotlin
1313
@Serializable
14-
data class TestDoc(val id: String, val name: String, val point: List<Double>)
14+
data class TestGeoDoc(val id: String, val name: String, val point: List<Double>)
15+
```
1516

17+
```kotlin
1618
client.createIndex(indexName) {
1719
mappings {
18-
keyword(TestDoc::id)
19-
text(TestDoc::name)
20-
geoPoint(TestDoc::point)
20+
keyword(TestGeoDoc::id)
21+
text(TestGeoDoc::name)
22+
geoPoint(TestGeoDoc::point)
2123
}
2224
}
2325
val points = listOf(
24-
TestDoc(
26+
TestGeoDoc(
2527
id = "bar",
2628
name = "Kommerzpunk",
2729
point = listOf(13.400544, 52.530286)
2830
),
29-
TestDoc(
31+
TestGeoDoc(
3032
id = "tower",
3133
name = "Tv Tower",
3234
point = listOf(13.40942173843226, 52.52082388531597)
3335
),
34-
TestDoc(
36+
TestGeoDoc(
3537
id = "tor",
3638
name = "Brandenburger Tor",
3739
point = listOf(13.377622382132417, 52.51632993824314)
3840
),
39-
TestDoc(
41+
TestGeoDoc(
4042
id = "tegel",
41-
name = "Tegel Airport",
43+
name = "Tegel Airport (Closed)",
4244
point = listOf(13.292043211510515, 52.55955614073912)
4345
),
44-
TestDoc(
46+
TestGeoDoc(
4547
id = "airport",
4648
name = "Brandenburg Airport",
4749
point = listOf(13.517282872748005, 52.367036750575814)
@@ -60,19 +62,19 @@ Bounding box searches return everything inside a bounding box specified by a top
6062

6163
```kotlin
6264
client.search(indexName) {
63-
query = GeoBoundingBoxQuery(TestDoc::point) {
65+
query = GeoBoundingBoxQuery(TestGeoDoc::point) {
6466
topLeft(points["tegel"]!!.point)
6567
bottomRight(points["airport"]!!.point)
6668
}
67-
}.parseHits(TestDoc.serializer()).map {
69+
}.parseHits(TestGeoDoc.serializer()).map {
6870
it.id
6971
}
7072
```
7173

7274
You can specify points in a variety of ways:
7375

7476
```kotlin
75-
GeoBoundingBoxQuery(TestDoc::point) {
77+
GeoBoundingBoxQuery(TestGeoDoc::point) {
7678
topLeft(latitude = 52.0, longitude = 13.0)
7779
// geojson coordinates
7880
topLeft(arrayOf(13.0, 52.0))
@@ -92,8 +94,8 @@ Searching by distance is also possible.
9294

9395
```kotlin
9496
client.search(indexName) {
95-
query = GeoDistanceQuery(TestDoc::point, "3km", points["tower"]!!.point)
96-
}.parseHits(TestDoc.serializer()).map {
97+
query = GeoDistanceQuery(TestGeoDoc::point, "3km", points["tower"]!!.point)
98+
}.parseHits(TestGeoDoc.serializer()).map {
9799
it.id
98100
}
99101
```
@@ -120,14 +122,14 @@ val polygon = Shape.Polygon(
120122
)
121123

122124
client.search(indexName) {
123-
query = GeoShapeQuery(TestDoc::point) {
125+
query = GeoShapeQuery(TestGeoDoc::point) {
124126
shape = polygon
125127
relation = GeoShapeQuery.Relation.contains
126128
}
127129
}
128130

129131
client.search(indexName) {
130-
query = GeoShapeQuery(TestDoc::point) {
132+
query = GeoShapeQuery(TestGeoDoc::point) {
131133
// you can also use string literals for the geometry
132134
// this is useful if you have some other representation
133135
// of geojson that you can serialize to string
@@ -147,7 +149,7 @@ client.search(indexName) {
147149
)
148150
relation = GeoShapeQuery.Relation.intersects
149151
}
150-
}.parseHits(TestDoc.serializer()).map {
152+
}.parseHits(TestGeoDoc.serializer()).map {
151153
it.id
152154
}
153155
```
@@ -160,20 +162,20 @@ this is translated into another geo_shape query.
160162

161163
```kotlin
162164
client.search(indexName) {
163-
query = GeoGridQuery(TestDoc::point) {
165+
query = GeoGridQuery(TestGeoDoc::point) {
164166
geotile = "6/50/50"
165167
}
166168
}
167169
client.search(indexName) {
168-
query = GeoGridQuery(TestDoc::point) {
170+
query = GeoGridQuery(TestGeoDoc::point) {
169171
geohex = "8a283082a677fff"
170172
}
171173
}
172174
client.search(indexName) {
173-
query = GeoGridQuery(TestDoc::point) {
175+
query = GeoGridQuery(TestGeoDoc::point) {
174176
geohash = "u33d"
175177
}
176-
}.parseHits(TestDoc.serializer()).map {
178+
}.parseHits(TestGeoDoc.serializer()).map {
177179
it.id
178180
}
179181
```

manual/Highlighting.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ client.search(indexName) {
2020
```
2121

2222
{
23-
"took": 43,
23+
"took": 41,
2424
"_shards": {
2525
"total": 1,
2626
"successful": 1,
@@ -80,7 +80,7 @@ client.search(indexName) {
8080
```
8181

8282
{
83-
"took": 19,
83+
"took": 16,
8484
"_shards": {
8585
"total": 1,
8686
"successful": 1,

0 commit comments

Comments
 (0)