Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option for polygon/linestring in results #823

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
3 changes: 3 additions & 0 deletions app/es_embedded/es/mappings.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@
"coordinate": {
"type": "geo_point"
},
"geometry": {
"type": "geo_shape"
},
"country": {
"properties": {
"default": {
Expand Down
11 changes: 9 additions & 2 deletions app/es_embedded/src/main/java/de/komoot/photon/Server.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public class Server {
private static final String FIELD_VERSION = "database_version";
private static final String FIELD_LANGUAGES = "indexed_languages";
private static final String FIELD_IMPORT_DATE = "import_date";
private static final String FIELD_SUPPORT_POLYGONS = "support_polygons";

private Node esNode;

Expand Down Expand Up @@ -169,7 +170,7 @@ private void setupDirectories(URL directoryName) throws IOException, URISyntaxEx

}

public DatabaseProperties recreateIndex(String[] languages, Date importDate, boolean supportStructuredQueries) throws IOException {
public DatabaseProperties recreateIndex(String[] languages, Date importDate, boolean supportStructuredQueries, boolean supportPolygons) throws IOException {
deleteIndex();

loadIndexSettings().createIndex(esClient, PhotonIndex.NAME);
Expand All @@ -178,7 +179,9 @@ public DatabaseProperties recreateIndex(String[] languages, Date importDate, boo

DatabaseProperties dbProperties = new DatabaseProperties()
.setLanguages(languages)
.setImportDate(importDate);
.setImportDate(importDate)
.setSupportPolygons(supportPolygons);

saveToDatabase(dbProperties);

return dbProperties;
Expand Down Expand Up @@ -234,6 +237,7 @@ public void saveToDatabase(DatabaseProperties dbProperties) throws IOException
.field(FIELD_VERSION, DatabaseProperties.DATABASE_VERSION)
.field(FIELD_LANGUAGES, String.join(",", dbProperties.getLanguages()))
.field(FIELD_IMPORT_DATE, dbProperties.getImportDate() instanceof Date ? dbProperties.getImportDate().toInstant() : null)
.field(FIELD_SUPPORT_POLYGONS, Boolean.toString(dbProperties.getSupportPolygons()))
.endObject().endObject();

esClient.prepareIndex(PhotonIndex.NAME, PhotonIndex.TYPE).
Expand Down Expand Up @@ -274,6 +278,9 @@ public void loadFromDatabase(DatabaseProperties dbProperties) {

String importDateString = properties.get(FIELD_IMPORT_DATE);
dbProperties.setImportDate(importDateString == null ? null : Date.from(Instant.parse(importDateString)));

String supportPolygons = properties.get(FIELD_SUPPORT_POLYGONS);
dbProperties.setSupportPolygons(supportPolygons == null ? null : Boolean.parseBoolean(supportPolygons));
}

public Importer createImporter(String[] languages, String[] extraTags) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@
import de.komoot.photon.Constants;
import de.komoot.photon.PhotonDoc;
import de.komoot.photon.nominatim.model.AddressType;

import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.io.geojson.GeoJsonWriter;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
Expand Down Expand Up @@ -38,6 +44,17 @@ public static XContentBuilder convert(PhotonDoc doc, String[] languages, String[
.endObject();
}

if (doc.getGeometry() != null) {
GeoJsonWriter g = new GeoJsonWriter();

XContentParser parser = JsonXContent
.jsonXContent
.createParser(NamedXContentRegistry.EMPTY, g.write(doc.getGeometry()));

builder.field("geometry");
builder.copyCurrentStructure(parser);
}

if (doc.getHouseNumber() != null) {
builder.field("housenumber", doc.getHouseNumber());
}
Expand Down
16 changes: 11 additions & 5 deletions app/es_embedded/src/test/java/de/komoot/photon/ESBaseTester.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import de.komoot.photon.searcher.PhotonResult;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.io.TempDir;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKTReader;

import java.io.IOException;
import java.nio.file.Path;
Expand All @@ -25,9 +27,9 @@ public class ESBaseTester {

private ElasticTestServer server;

protected PhotonDoc createDoc(double lon, double lat, int id, int osmId, String key, String value) {
protected PhotonDoc createDoc(double lon, double lat, int id, int osmId, String key, String value) throws ParseException {
Point location = FACTORY.createPoint(new Coordinate(lon, lat));
return new PhotonDoc(id, "W", osmId, key, value).names(Collections.singletonMap("name", "berlin")).centroid(location);
return new PhotonDoc(id, "W", osmId, key, value).names(Collections.singletonMap("name", "berlin")).centroid(location).geometry(new WKTReader().read("POLYGON ((6.4440619 52.1969454, 6.4441094 52.1969158, 6.4441408 52.1969347, 6.4441138 52.1969516, 6.4440933 52.1969643, 6.4440619 52.1969454))"));
}

protected PhotonResult getById(int id) {
Expand All @@ -45,17 +47,21 @@ public void tearDown() throws IOException {
}

public void setUpES() throws IOException {
setUpES(dataDirectory, "en");
setUpES(dataDirectory, false,"en");
}

public void setUpESWithPolygons() throws IOException {
setUpES(dataDirectory, true,"en");
}
/**
* Setup the ES server
*
* @throws IOException
*/
public void setUpES(Path test_directory, String... languages) throws IOException {
public void setUpES(Path test_directory, boolean supportPolygons, String... languages) throws IOException {
server = new ElasticTestServer(test_directory.toString());
server.start(TEST_CLUSTER_NAME, new String[]{});
server.recreateIndex(languages, new Date(), false);
server.recreateIndex(languages, new Date(), false, supportPolygons);
refresh();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ protected PhotonDoc createDoc(double lon, double lat, int id, int osmId, String

@BeforeAll
void setUp() throws Exception {
setUpES(instanceTestDirectory, "en", "de", "fr", "it");
setUpES(instanceTestDirectory, false, "en", "de", "fr", "it");
Importer instance = getServer().createImporter(new String[]{"en", "de", "fr", "it"},
new String[]{"population", "capital"});

Expand Down
6 changes: 4 additions & 2 deletions app/opensearch/src/main/java/de/komoot/photon/Server.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public void shutdown() {
}
}

public DatabaseProperties recreateIndex(String[] languages, Date importDate, boolean supportStructuredQueries) throws IOException {
public DatabaseProperties recreateIndex(String[] languages, Date importDate, boolean supportStructuredQueries, boolean supportPolygons) throws IOException {
// delete any existing data
if (client.indices().exists(e -> e.index(PhotonIndex.NAME)).value()) {
client.indices().delete(d -> d.index(PhotonIndex.NAME));
Expand All @@ -111,7 +111,8 @@ public DatabaseProperties recreateIndex(String[] languages, Date importDate, boo
var dbProperties = new DatabaseProperties()
.setLanguages(languages)
.setSupportStructuredQueries(supportStructuredQueries)
.setImportDate(importDate);
.setImportDate(importDate)
.setSupportPolygons(supportPolygons);
saveToDatabase(dbProperties);

return dbProperties;
Expand Down Expand Up @@ -157,6 +158,7 @@ public void loadFromDatabase(DatabaseProperties dbProperties) throws IOException
dbProperties.setLanguages(dbEntry.source().languages);
dbProperties.setImportDate(dbEntry.source().importDate);
dbProperties.setSupportStructuredQueries(dbEntry.source().supportStructuredQueries);
dbProperties.setSupportPolygons(dbEntry.source().supportPolygons);
}

public Importer createImporter(String[] languages, String[] extraTags) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class DBPropertyEntry {
public Date importDate;
public String[] languages;
public boolean supportStructuredQueries;
public boolean supportPolygons;

public DBPropertyEntry() {}

Expand All @@ -17,5 +18,6 @@ public DBPropertyEntry(DatabaseProperties props) {
importDate = props.getImportDate();
languages = props.getLanguages();
supportStructuredQueries = props.getSupportStructuredQueries();
supportPolygons = props.getSupportPolygons();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ private void setupBaseMappings() {
}

mappings.properties("coordinate", b -> b.geoPoint(p -> p));
mappings.properties("geometry", b -> b.geoShape(p -> p));
mappings.properties("countrycode", b -> b.keyword(p -> p.index(true)));
mappings.properties("importance", b -> b.float_(p -> p.index(false)));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import de.komoot.photon.PhotonDoc;
import de.komoot.photon.Utils;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.io.geojson.GeoJsonWriter;

import java.io.IOException;
import java.util.HashMap;
Expand Down Expand Up @@ -48,6 +49,11 @@ public void serialize(PhotonDoc value, JsonGenerator gen, SerializerProvider pro
gen.writeEndObject();
}

if (value.getGeometry() != null) {
GeoJsonWriter g = new GeoJsonWriter();
gen.writeObjectField("geometry", g.write(value.getGeometry()));
}

if (value.getHouseNumber() != null) {
gen.writeStringField("housenumber", value.getHouseNumber());
}
Expand Down
14 changes: 8 additions & 6 deletions app/opensearch/src/test/java/de/komoot/photon/ESBaseTester.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package de.komoot.photon;

import de.komoot.photon.opensearch.Importer;
import de.komoot.photon.opensearch.OpenSearchTestServer;
import de.komoot.photon.opensearch.Updater;
import de.komoot.photon.searcher.PhotonResult;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.io.TempDir;
Expand Down Expand Up @@ -49,28 +51,28 @@ public void setUpES() throws IOException {
public void setUpES(Path test_directory, String... languages) throws IOException {
server = new OpenSearchTestServer(test_directory.toString());
server.startTestServer(TEST_CLUSTER_NAME);
server.recreateIndex(languages, new Date(), true);
server.recreateIndex(languages, new Date(), true, true);
server.refreshIndexes();
}

protected Importer makeImporter() {
return server.createImporter(new String[]{"en"}, new String[]{});
return (Importer) server.createImporter(new String[]{"en"}, new String[]{});
}

protected Importer makeImporterWithExtra(String... extraTags) {
return server.createImporter(new String[]{"en"}, extraTags);
return (Importer) server.createImporter(new String[]{"en"}, extraTags);
}

protected Importer makeImporterWithLanguages(String... languages) {
return server.createImporter(languages, new String[]{});
return (Importer) server.createImporter(languages, new String[]{});
}

protected Updater makeUpdater() {
return server.createUpdater(new String[]{"en"}, new String[]{});
return (Updater) server.createUpdater(new String[]{"en"}, new String[]{});
}

protected Updater makeUpdaterWithExtra(String... extraTags) {
return server.createUpdater(new String[]{"en"}, extraTags);
return (Updater) server.createUpdater(new String[]{"en"}, extraTags);
}

protected Server getServer() {
Expand Down
3 changes: 3 additions & 0 deletions buildSrc/shared.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ application {
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
compileJava.options.encoding = "UTF-8"
compileTestJava.options.encoding = "UTF-8"
}

repositories {
Expand Down Expand Up @@ -52,6 +54,7 @@ dependencies {
exclude(module: 'commons-logging')
}
implementation 'org.locationtech.jts:jts-core:1.19.0'
implementation 'org.locationtech.jts.io:jts-io-common:1.19.0'
implementation 'com.sparkjava:spark-core:2.9.4'
implementation 'net.postgis:postgis-jdbc:2023.1.0'
implementation 'org.json:json:20240303'
Expand Down
22 changes: 15 additions & 7 deletions src/main/java/de/komoot/photon/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ private static void startJsonDump(CommandLineArgs args) {
try {
final String filename = args.getJsonDump();
final JsonDumper jsonDumper = new JsonDumper(filename, args.getLanguages(), args.getExtraTags());
NominatimConnector nominatimConnector = new NominatimConnector(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword());
NominatimConnector nominatimConnector = new NominatimConnector(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.getImportGeometryColumn());
nominatimConnector.setImporter(jsonDumper);
nominatimConnector.readEntireDatabase(args.getCountryCodes());
LOGGER.info("Json dump was created: {}", filename);
Expand All @@ -117,10 +117,14 @@ private static void startJsonDump(CommandLineArgs args) {
*/
private static void startNominatimImport(CommandLineArgs args, Server esServer) {
DatabaseProperties dbProperties;
NominatimConnector nominatimConnector = new NominatimConnector(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword());
NominatimConnector nominatimConnector = new NominatimConnector(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.getImportGeometryColumn());
Date importDate = nominatimConnector.getLastImportDate();
LOGGER.info("Starting import with the following settings: " +
"\n Languages: {} \n Import Date: {} \n Support Structured Queries: {} \n Support Polygons: {}",
args.getLanguages(), importDate, args.getSupportStructuredQueries(), args.getImportGeometryColumn());

try {
dbProperties = esServer.recreateIndex(args.getLanguages(), importDate, args.getSupportStructuredQueries()); // clear out previous data
dbProperties = esServer.recreateIndex(args.getLanguages(), importDate, args.getSupportStructuredQueries(), args.getImportGeometryColumn()); // clear out previous data
} catch (IOException e) {
throw new RuntimeException("Cannot setup index, elastic search config files not readable", e);
}
Expand All @@ -133,7 +137,7 @@ private static void startNominatimImport(CommandLineArgs args, Server esServer)
}

private static void startNominatimUpdateInit(CommandLineArgs args) {
NominatimUpdater nominatimUpdater = new NominatimUpdater(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword());
NominatimUpdater nominatimUpdater = new NominatimUpdater(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.getImportGeometryColumn());
nominatimUpdater.initUpdates(args.getNominatimUpdateInit());
}

Expand All @@ -160,7 +164,7 @@ private static NominatimUpdater setupNominatimUpdater(CommandLineArgs args, Serv
DatabaseProperties dbProperties = new DatabaseProperties();
server.loadFromDatabase(dbProperties);

NominatimUpdater nominatimUpdater = new NominatimUpdater(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword());
NominatimUpdater nominatimUpdater = new NominatimUpdater(args.getHost(), args.getPort(), args.getDatabase(), args.getUser(), args.getPassword(), args.getImportGeometryColumn());
nominatimUpdater.setUpdater(server.createUpdater(dbProperties.getLanguages(), args.getExtraTags()));
return nominatimUpdater;
}
Expand All @@ -176,6 +180,10 @@ private static void startApi(CommandLineArgs args, Server server) throws IOExcep
dbProperties.restrictLanguages(args.getLanguages());
}

LOGGER.info("Starting API with the following settings: " +
"\n Languages: {} \n Import Date: {} \n Support Structured Queries: {} \n Support Polygons: {}",
dbProperties.getLanguages(), dbProperties.getImportDate(), dbProperties.getSupportStructuredQueries(), dbProperties.getSupportPolygons());

port(args.getListenPort());
ipAddress(args.getListenIp());

Expand All @@ -191,8 +199,8 @@ private static void startApi(CommandLineArgs args, Server server) throws IOExcep
String[] langs = dbProperties.getLanguages();

SearchHandler searchHandler = server.createSearchHandler(langs, args.getQueryTimeout());
get("api", new SearchRequestHandler("api", searchHandler, langs, args.getDefaultLanguage(), args.getMaxResults()));
get("api/", new SearchRequestHandler("api/", searchHandler, langs, args.getDefaultLanguage(), args.getMaxResults()));
get("api", new SearchRequestHandler("api", searchHandler, langs, args.getDefaultLanguage(), args.getMaxResults(), dbProperties.getSupportPolygons()));
get("api/", new SearchRequestHandler("api/", searchHandler, langs, args.getDefaultLanguage(), args.getMaxResults(), dbProperties.getSupportPolygons()));

if (dbProperties.getSupportStructuredQueries()) {
StructuredSearchHandler structured = server.createStructuredSearchHandler(langs, args.getQueryTimeout());
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/de/komoot/photon/CommandLineArgs.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ public class CommandLineArgs {
@Parameter(names = "-max-reverse-results", description = "The maximum possible 'limit' parameter for reverse geocoding searches")
private int maxReverseResults = 50;

@Parameter(names = "-import-geometry-column", description = "[import-only] Add the 'geometry' column from Nominatim on import (i.e. add Polygons for cities, countries etc.). WARNING: This will increase the Elasticsearch Index size! (~575GB for Planet)")
private boolean importGeometryColumn = false;

public String[] getLanguages(boolean useDefaultIfEmpty) {
if (useDefaultIfEmpty && languages.length == 0) {
return new String[]{"en", "de", "fr", "it"};
Expand Down Expand Up @@ -204,5 +207,9 @@ public int getMaxReverseResults() {
public int getMaxResults() {
return maxResults;
}

public boolean getImportGeometryColumn() {
return importGeometryColumn;
}
}

21 changes: 21 additions & 0 deletions src/main/java/de/komoot/photon/DatabaseProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public class DatabaseProperties {

private boolean supportStructuredQueries;

private boolean supportPolygons;

/**
* Return the list of languages for which the database is configured.
* @return
Expand Down Expand Up @@ -100,4 +102,23 @@ public DatabaseProperties setSupportStructuredQueries(boolean supportStructuredQ
this.supportStructuredQueries = supportStructuredQueries;
return this;
}

public boolean getSupportPolygons() {
return supportPolygons;
}

public DatabaseProperties setSupportPolygons(boolean supportPolygons) {
this.supportPolygons = supportPolygons;
return this;
}

@Override
public String toString() {
return "DatabaseProperties{" +
"languages=" + Arrays.toString(languages) +
", importDate=" + importDate +
", supportStructuredQueries=" + supportStructuredQueries +
", supportPolygons=" + supportPolygons +
'}';
}
}
Loading