This is an automated email from the ASF dual-hosted git repository.

perdjesk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-baremaps.git


The following commit(s) were added to refs/heads/main by this push:
     new 5ad51917 Experimental GeocoderOSM (#780)
5ad51917 is described below

commit 5ad519171dda6d66f48be96417b44c7682d95b8c
Author: Perdjesk <[email protected]>
AuthorDate: Wed Sep 13 10:59:01 2023 +0200

    Experimental GeocoderOSM (#780)
    
    An experimental geocoder using OSM data in a Lucene index
---
 .../geocoderosm/GeocoderOsmConsumerEntity.java     |  45 ++++++
 .../geocoderosm/GeocoderOsmDocumentMapper.java     | 100 +++++++++++++
 .../baremaps/geocoderosm/GeocoderOsmQuery.java     |  40 +++++
 .../org/apache/baremaps/geocoderosm/OsmTags.java   |  36 +++++
 .../apache/baremaps/geocoderosm/package-info.java  |   4 +
 .../function/RelationGeometryBuilder.java          |   6 +-
 .../tasks/CreateGeocoderOpenStreetMap.java         | 126 ++++++++++++++++
 .../apache/baremaps/geocoderosm/OSMIndexTest.java  | 162 +++++++++++++++++++++
 baremaps-core/src/test/resources/log4j2-test.yaml  |  13 ++
 9 files changed, 530 insertions(+), 2 deletions(-)

diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/geocoderosm/GeocoderOsmConsumerEntity.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/geocoderosm/GeocoderOsmConsumerEntity.java
new file mode 100644
index 00000000..c8b32f1b
--- /dev/null
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/geocoderosm/GeocoderOsmConsumerEntity.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
KIND, either express
+ * or implied. See the License for the specific language governing permissions 
and limitations under
+ * the License.
+ */
+
+package org.apache.baremaps.geocoderosm;
+
+import java.util.function.Consumer;
+import org.apache.baremaps.openstreetmap.model.Element;
+import org.apache.baremaps.openstreetmap.model.Entity;
+import org.apache.lucene.index.IndexWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GeocoderOsmConsumerEntity implements Consumer<Entity> {
+  private final IndexWriter indexWriter;
+  private final GeocoderOsmDocumentMapper geocoderOsmDocumentMapper =
+      new GeocoderOsmDocumentMapper();
+
+  private static final Logger logger = 
LoggerFactory.getLogger(GeocoderOsmConsumerEntity.class);
+
+  public GeocoderOsmConsumerEntity(IndexWriter indexWriter) {
+    this.indexWriter = indexWriter;
+  }
+
+  @Override
+  public void accept(Entity entity) {
+    try {
+      if (entity instanceof Element element) {
+        var document = geocoderOsmDocumentMapper.apply(element);
+        indexWriter.addDocument(document);
+      }
+    } catch (Exception e) {
+      // Tolerate the failure of processing an element, partial data failure 
mode
+      logger.warn("The following OSM entity ({}) is not processed due to {}", 
entity, e);
+    }
+  }
+}
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/geocoderosm/GeocoderOsmDocumentMapper.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/geocoderosm/GeocoderOsmDocumentMapper.java
new file mode 100644
index 00000000..50117332
--- /dev/null
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/geocoderosm/GeocoderOsmDocumentMapper.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
KIND, either express
+ * or implied. See the License for the specific language governing permissions 
and limitations under
+ * the License.
+ */
+
+package org.apache.baremaps.geocoderosm;
+
+
+
+import java.util.function.Function;
+import org.apache.baremaps.openstreetmap.model.Element;
+import org.apache.baremaps.openstreetmap.model.Node;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.LatLonShape;
+import org.apache.lucene.document.NumericDocValuesField;
+import org.apache.lucene.document.StoredField;
+import org.apache.lucene.document.TextField;
+import org.apache.lucene.geo.Polygon;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.io.geojson.GeoJsonWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class GeocoderOsmDocumentMapper implements Function<Element, Document> {
+  private static final Logger logger = 
LoggerFactory.getLogger(GeocoderOsmDocumentMapper.class);
+
+  @Override
+  public Document apply(Element element) {
+    var document = new Document();
+    document.add(new StoredField("osm_id", element.id()));
+    document.add(new StoredField("osm_type", 
element.getClass().getSimpleName()));
+
+    if (element.getTags().containsKey(OsmTags.NAME.key())) {
+      document.add(
+          new TextField(OsmTags.NAME.key(), 
element.getTags().get(OsmTags.NAME.key()).toString(),
+              Field.Store.YES));
+    }
+
+    if (element instanceof Node node) {
+      document.add(LatLonShape.createIndexableFields("polygon", node.getLat(), 
node.getLon())[0]);
+      document.add(new StoredField("latitude", node.getLat()));
+      document.add(new StoredField("longitude", node.getLon()));
+    }
+    if (element.getGeometry() != null
+        && 
element.getGeometry().getGeometryType().equals(Geometry.TYPENAME_LINESTRING)) {
+      logger.debug("Geometry linestring ignored as not supported by Lucene 
Polygon.fromGeoJson: {}",
+          element);
+    }
+    if (element.getGeometry() != null
+        && 
!element.getGeometry().getGeometryType().equals(Geometry.TYPENAME_POINT)
+        && 
!element.getGeometry().getGeometryType().equals(Geometry.TYPENAME_LINESTRING)) {
+      // JTS to GeoJSON
+      var geojsonWriter = new GeoJsonWriter();
+      // Remove crs field in GeoJSON as the field content is incompatible 
between
+      // Lucene Polygon.fromGeoJSON and GeoJsonWriter.
+      // Avoid "crs must be CRS84 from OGC, but saw: EPSG:4326"
+      // See:
+      // 
https://github.com/apache/lucene/blob/ef42af65f27f7f078b1ab426de9f2b2fa214ad86/lucene/core/src/java/org/apache/lucene/geo/SimpleGeoJSONPolygonParser.java#L180
+      // 
https://github.com/locationtech/jts/blob/ee59b591f15b5150516393d3ba0b49e46a113fc9/modules/io/common/src/main/java/org/locationtech/jts/io/geojson/GeoJsonWriter.java#L226
+      geojsonWriter.setEncodeCRS(false);
+      // Assume that Geometry is in EPSG:4326/WGS84 for Lucene 
Polygon.fromGeoJSON
+      var geojson = geojsonWriter.write(element.getGeometry());
+
+      // GeoJSON to Lucene Polygon
+      try {
+        var polygons = Polygon.fromGeoJSON(geojson);
+
+        for (Polygon polygon : polygons) {
+          // LatLonShape.createIndexableFields can create multiple polygons 
out of a single polygon
+          // through tesselation
+          for (Field field : LatLonShape.createIndexableFields("polygon", 
polygon)) {
+            document.add(field);
+          }
+        }
+      } catch (Exception e) {
+        // ignore geometry
+        logger.debug("Geometry ({}) failed indexing caused by: {}",
+            element, e);
+      }
+
+    }
+
+    if (element.getTags().containsKey(OsmTags.POPULATION.key())) {
+      var population = 
Long.parseLong(element.getTags().get(OsmTags.POPULATION.key()).toString());
+      document.add(new NumericDocValuesField(OsmTags.POPULATION.key(), 
population));
+      document.add(new StoredField(OsmTags.POPULATION.key(), population));
+    }
+    return document;
+  }
+
+}
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/geocoderosm/GeocoderOsmQuery.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/geocoderosm/GeocoderOsmQuery.java
new file mode 100644
index 00000000..85c8f69d
--- /dev/null
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/geocoderosm/GeocoderOsmQuery.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
KIND, either express
+ * or implied. See the License for the specific language governing permissions 
and limitations under
+ * the License.
+ */
+
+package org.apache.baremaps.geocoderosm;
+
+import org.apache.baremaps.geocoder.GeocoderConstants;
+import org.apache.lucene.queryparser.classic.QueryParser;
+import org.apache.lucene.queryparser.simple.SimpleQueryParser;
+import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.Query;
+
+public class GeocoderOsmQuery {
+
+  private final String query;
+
+  public GeocoderOsmQuery(String query) {
+    this.query = query;
+  }
+
+  public Query build() {
+    var builder = new BooleanQuery.Builder();
+    var queryTextEsc = QueryParser.escape(query);
+
+    var parser = new SimpleQueryParser(GeocoderConstants.ANALYZER, 
OsmTags.NAME.key());
+    var termsQuery = parser.parse(queryTextEsc);
+    // at least one terms of the queryText must be present
+    builder.add(termsQuery, BooleanClause.Occur.MUST);
+    return builder.build();
+  }
+}
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/geocoderosm/OsmTags.java 
b/baremaps-core/src/main/java/org/apache/baremaps/geocoderosm/OsmTags.java
new file mode 100644
index 00000000..22f2918c
--- /dev/null
+++ b/baremaps-core/src/main/java/org/apache/baremaps/geocoderosm/OsmTags.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
KIND, either express
+ * or implied. See the License for the specific language governing permissions 
and limitations under
+ * the License.
+ */
+
+package org.apache.baremaps.geocoderosm;
+
+public enum OsmTags {
+  NAME("name"),
+  PLACE("place"),
+  POPULATION("population"),
+  LATITUDE("latitude"),
+  LONGITUDE("longitude");
+
+  private final String key;
+
+  OsmTags(String key) {
+    this.key = key;
+  }
+
+  @Override
+  public String toString() {
+    return key;
+  }
+
+  public String key() {
+    return key;
+  }
+}
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/geocoderosm/package-info.java 
b/baremaps-core/src/main/java/org/apache/baremaps/geocoderosm/package-info.java
new file mode 100644
index 00000000..6f6a4a30
--- /dev/null
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/geocoderosm/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Experimental Geocoder based on OpenStreetMap data using a Lucene index.
+ */
+package org.apache.baremaps.geocoderosm;
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/RelationGeometryBuilder.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/RelationGeometryBuilder.java
index 1ca50afe..773a516f 100644
--- 
a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/RelationGeometryBuilder.java
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/RelationGeometryBuilder.java
@@ -59,12 +59,14 @@ public class RelationGeometryBuilder implements 
Consumer<Relation> {
 
       Map<String, Object> tags = relation.getTags();
 
-      // Filter multipolygon geometries
-      if (!"multipolygon".equals(tags.get("type"))) {
+      // Filter out type that are not multipolygon or boundary geometries
+      if (!("multipolygon".equals(tags.get("type"))
+          || "boundary".equals(tags.get("type")))) {
         return;
       }
 
       // Filter coastline geometries
+      // TODO: document motivation for filtering out.
       if ("coastline".equals(tags.get("natural"))) {
         return;
       }
diff --git 
a/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/CreateGeocoderOpenStreetMap.java
 
b/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/CreateGeocoderOpenStreetMap.java
new file mode 100644
index 00000000..a3a7777e
--- /dev/null
+++ 
b/baremaps-core/src/main/java/org/apache/baremaps/workflow/tasks/CreateGeocoderOpenStreetMap.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
KIND, either express
+ * or implied. See the License for the specific language governing permissions 
and limitations under
+ * the License.
+ */
+
+package org.apache.baremaps.workflow.tasks;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import org.apache.baremaps.database.collection.AppendOnlyBuffer;
+import org.apache.baremaps.database.collection.DataMap;
+import org.apache.baremaps.database.collection.MemoryAlignedDataList;
+import org.apache.baremaps.database.collection.MemoryAlignedDataMap;
+import org.apache.baremaps.database.collection.MonotonicDataMap;
+import org.apache.baremaps.database.memory.MemoryMappedDirectory;
+import org.apache.baremaps.database.type.LongDataType;
+import org.apache.baremaps.database.type.LongListDataType;
+import org.apache.baremaps.database.type.PairDataType;
+import org.apache.baremaps.database.type.geometry.LonLatDataType;
+import org.apache.baremaps.geocoder.GeocoderConstants;
+import org.apache.baremaps.geocoderosm.GeocoderOsmConsumerEntity;
+import org.apache.baremaps.openstreetmap.pbf.PbfEntityReader;
+import org.apache.baremaps.stream.StreamUtils;
+import org.apache.baremaps.utils.FileUtils;
+import org.apache.baremaps.workflow.Task;
+import org.apache.baremaps.workflow.WorkflowContext;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.store.FSDirectory;
+import org.locationtech.jts.geom.Coordinate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Experimental feature.
+ * 
+ * @see org.apache.baremaps.geocoderosm
+ */
+public record CreateGeocoderOpenStreetMap(Path file, Path indexDirectory)
+    implements
+      Task {
+
+  private static final Logger logger = 
LoggerFactory.getLogger(CreateGeocoderOpenStreetMap.class);
+
+  @Override
+  public void execute(WorkflowContext context) throws Exception {
+
+    var path = file.toAbsolutePath();
+
+
+    var cacheDir = Files.createTempDirectory(Paths.get("."), "cache_");
+
+    DataMap<Long, Coordinate> coordinateMap;
+    if (Files.size(path) > 1 << 30) {
+      var coordinateDir = 
Files.createDirectories(cacheDir.resolve("coordinate_keys"));
+      coordinateMap = new MemoryAlignedDataMap<>(
+          new LonLatDataType(),
+          new MemoryMappedDirectory(coordinateDir));
+    } else {
+      var coordinateKeysDir = 
Files.createDirectories(cacheDir.resolve("coordinate_keys"));
+      var coordinateValuesDir = 
Files.createDirectories(cacheDir.resolve("coordinate_vals"));
+      coordinateMap =
+          new MonotonicDataMap<>(
+              new MemoryAlignedDataList<>(
+                  new PairDataType<>(new LongDataType(), new LongDataType()),
+                  new MemoryMappedDirectory(coordinateKeysDir)),
+              new AppendOnlyBuffer<>(
+                  new LonLatDataType(),
+                  new MemoryMappedDirectory(coordinateValuesDir)));
+    }
+
+    var referenceKeysDir = 
Files.createDirectory(cacheDir.resolve("reference_keys"));
+    var referenceValuesDir = 
Files.createDirectory(cacheDir.resolve("reference_vals"));
+    var referenceMap =
+        new MonotonicDataMap<>(
+            new MemoryAlignedDataList<>(
+                new PairDataType<>(new LongDataType(), new LongDataType()),
+                new MemoryMappedDirectory(referenceKeysDir)),
+            new AppendOnlyBuffer<>(
+                new LongListDataType(),
+                new MemoryMappedDirectory(referenceValuesDir)));
+
+    var directory = FSDirectory.open(indexDirectory);
+    var config = new IndexWriterConfig(GeocoderConstants.ANALYZER);
+
+    try (var indexWriter = new IndexWriter(directory, config)) {
+      var importer = new GeocoderOsmConsumerEntity(indexWriter);
+      execute(
+          path,
+          coordinateMap,
+          referenceMap,
+          importer);
+    }
+    FileUtils.deleteRecursively(cacheDir);
+  }
+
+  public static void execute(
+      Path path,
+      DataMap<Long, Coordinate> coordinateMap,
+      DataMap<Long, List<Long>> referenceMap,
+      GeocoderOsmConsumerEntity importer) throws IOException {
+
+    // configure the block reader
+    var reader = new PbfEntityReader()
+        .geometries(true)
+        // Must be to 4326 projection to avoid transformation before using 
Lucene API
+        .projection(4326)
+        .coordinateMap(coordinateMap)
+        .referenceMap(referenceMap);
+
+    try (var input = Files.newInputStream(path)) {
+      StreamUtils.batch(reader.stream(input)).forEach(importer);
+    }
+
+  }
+}
diff --git 
a/baremaps-core/src/test/java/org/apache/baremaps/geocoderosm/OSMIndexTest.java 
b/baremaps-core/src/test/java/org/apache/baremaps/geocoderosm/OSMIndexTest.java
new file mode 100644
index 00000000..7ef9319a
--- /dev/null
+++ 
b/baremaps-core/src/test/java/org/apache/baremaps/geocoderosm/OSMIndexTest.java
@@ -0,0 +1,162 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not 
use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software 
distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
KIND, either express
+ * or implied. See the License for the specific language governing permissions 
and limitations under
+ * the License.
+ */
+
+package org.apache.baremaps.geocoderosm;
+
+import static org.apache.baremaps.testing.TestFiles.LIECHTENSTEIN_OSM_PBF;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.apache.baremaps.utils.FileUtils;
+import org.apache.baremaps.workflow.WorkflowContext;
+import org.apache.baremaps.workflow.tasks.CreateGeocoderOpenStreetMap;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.LatLonShape;
+import org.apache.lucene.document.ShapeField;
+import org.apache.lucene.geo.Polygon;
+import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.FieldExistsQuery;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.ScoreDoc;
+import org.apache.lucene.search.SearcherFactory;
+import org.apache.lucene.search.SearcherManager;
+import org.apache.lucene.store.MMapDirectory;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+
+@Disabled("prototype implementation")
+public class OSMIndexTest {
+
+  private static Path directory;
+  private static IndexSearcher searcher;
+
+  @BeforeAll
+  public static void beforeAll() throws Exception {
+    // Init the geocoder service
+    directory = Files.createTempDirectory(Paths.get("."), "geocoder_");
+
+    // Create the geonames index
+
+    var task = new CreateGeocoderOpenStreetMap(LIECHTENSTEIN_OSM_PBF, 
directory);
+    task.execute(new WorkflowContext());
+    var dir = MMapDirectory.open(directory);
+    var searcherManager = new SearcherManager(dir, new SearcherFactory());
+    searcher = searcherManager.acquire();
+  }
+
+  @AfterAll
+  public static void afterAll() throws IOException {
+    FileUtils.deleteRecursively(directory);
+  }
+
+  @Test
+  void testCreateIndex() throws Exception {
+    var query =
+        new GeocoderOsmQuery("vaduz").build();
+    var topDocs = searcher.search(query, 1);
+    var doc = 
searcher.doc(Arrays.stream(topDocs.scoreDocs).findFirst().get().doc);
+    assertEquals("Vaduz", doc.getField("name").stringValue());
+    System.out.println(doc);
+  }
+
+
+  /**
+   * Querying document which contains a point with lat/long
+   */
+  @Test
+  void testGeoQuery() throws Exception {
+    var vaduzLatLong = new double[] {47.1392862, 9.5227962};
+    var query = LatLonShape.newPointQuery("polygon", 
ShapeField.QueryRelation.CONTAINS,
+        vaduzLatLong);
+    var topDocs = searcher.search(query, 10);
+    List<Document> docs = new ArrayList<>();
+    for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
+      docs.add(searcher.doc(scoreDoc.doc));
+    }
+    // Vaduz OSM relation:1155956 is present in results
+    // https://www.openstreetmap.org/relation/1155956
+    var vaduz = docs.stream()
+        .filter(doc -> Long.parseLong(doc.getField("osm_id").stringValue()) == 
1155956).findFirst();
+    assertTrue(vaduz.isPresent());
+    assertEquals("1155956", vaduz.get().get("osm_id"));
+
+    docs.forEach(System.out::println);
+  }
+
+  /**
+   * Querying document within a polygon shape drawn as a bounding box around 
Vaduz
+   */
+  @Test
+  void testPolygonQuery() throws Exception {
+    // Drawing box at https://geojson.io/#map=14.18/47.13807/9.5242
+    var bbox = """
+        {
+          "type": "FeatureCollection",
+          "features": [
+            {
+              "type": "Feature",
+              "properties": {},
+              "geometry": {
+                "coordinates": [
+                  [
+                    [
+                      9.503676237856723,
+                      47.14708630518214
+                    ],
+                    [
+                      9.503676237856723,
+                      47.1290480684377
+                    ],
+                    [
+                      9.544726212280978,
+                      47.1290480684377
+                    ],
+                    [
+                      9.544726212280978,
+                      47.14708630518214
+                    ],
+                    [
+                      9.503676237856723,
+                      47.14708630518214
+                    ]
+                  ]
+                ],
+                "type": "Polygon"
+              }
+            }
+          ]
+        }
+        """;
+    var polygon = Polygon.fromGeoJSON(bbox);
+    var query = LatLonShape.newPolygonQuery("polygon", 
ShapeField.QueryRelation.WITHIN, polygon);
+    var booleanQuery = new BooleanQuery.Builder();
+    booleanQuery.add(query, BooleanClause.Occur.MUST);
+    // Filter to only include document which have a name field
+    booleanQuery.add(new FieldExistsQuery("name"), BooleanClause.Occur.MUST);
+    var topDocs = searcher.search(booleanQuery.build(), 100);
+    for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
+      System.out.println(searcher.doc(scoreDoc.doc));
+    }
+  }
+
+}
diff --git a/baremaps-core/src/test/resources/log4j2-test.yaml 
b/baremaps-core/src/test/resources/log4j2-test.yaml
new file mode 100644
index 00000000..3232a582
--- /dev/null
+++ b/baremaps-core/src/test/resources/log4j2-test.yaml
@@ -0,0 +1,13 @@
+Configuration:
+  status: warn
+  appenders:
+    Console:
+      name: STDOUT
+      target: SYSTEM_OUT
+      PatternLayout:
+        Pattern: "[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n"
+  Loggers:
+    Root:
+      level: warn
+      AppenderRef:
+        ref: STDOUT

Reply via email to