Skip to content

Commit 738a285

Browse files
authored
Merge pull request #1030 from lonvia/custom-extra-info
Allow arbitrary JSON for extra fields
2 parents ca47acd + 2f64412 commit 738a285

18 files changed

+239
-217
lines changed

src/main/java/de/komoot/photon/ConfigExtraTags.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,21 @@ public ConfigExtraTags(List<String> tags) {
2626
this.tags = allowAll ? new String[0] : tags.toArray(String[]::new);
2727
}
2828

29-
public void writeFilteredExtraTags(JsonGenerator writer, String fieldName, Map<String, String> sourceTags) throws IOException {
29+
public void writeFilteredExtraTags(JsonGenerator writer, String fieldName, Map<String, Object> sourceTags) throws IOException {
3030
if (!sourceTags.isEmpty()) {
3131
if (allowAll) {
3232
writer.writeObjectField(fieldName, sourceTags);
3333
} else if (tags.length > 0) {
3434
boolean foundTag = false;
3535

3636
for (String tag : tags) {
37-
String value = sourceTags.get(tag);
37+
Object value = sourceTags.get(tag);
3838
if (value != null) {
3939
if (!foundTag) {
4040
writer.writeObjectFieldStart(fieldName);
4141
foundTag = true;
4242
}
43-
writer.writeStringField(tag, value);
43+
writer.writeObjectField(tag, value);
4444
}
4545
}
4646

@@ -51,7 +51,7 @@ public void writeFilteredExtraTags(JsonGenerator writer, String fieldName, Map<S
5151
}
5252
}
5353

54-
public Map<String, String> filterExtraTags(Map<String, String> sourceTags) {
54+
public Map<String, Object> filterExtraTags(Map<String, Object> sourceTags) {
5555
if (allowAll || sourceTags.isEmpty()) {
5656
return sourceTags;
5757
}
@@ -60,7 +60,7 @@ public Map<String, String> filterExtraTags(Map<String, String> sourceTags) {
6060
return Map.of();
6161
}
6262

63-
final Map<String, String> newMap = new HashMap<>();
63+
final Map<String, Object> newMap = new HashMap<>();
6464
for (var key : tags) {
6565
final var value = sourceTags.get(key);
6666
if (value != null) {

src/main/java/de/komoot/photon/PhotonDoc.java

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public class PhotonDoc {
5353

5454
private NameMap name = new NameMap();
5555
@Nullable private String postcode = null;
56-
private Map<String, String> extratags = Map.of();
56+
private Map<String, Object> extratags = Map.of();
5757
private Set<String> categorySet = Set.of();
5858
@Nullable private Envelope bbox = null;
5959
private double importance = 0;
@@ -156,21 +156,9 @@ public PhotonDoc countryCode(@Nullable String countryCode) {
156156
return this;
157157
}
158158

159-
public PhotonDoc extraTags(@Nullable Map<String, String> extratags) {
159+
public PhotonDoc extraTags(@Nullable Map<String, Object> extratags) {
160160
this.extratags = extratags == null ? Map.of() : extratags;
161161

162-
if (extratags != null) {
163-
String place = extratags.get("place");
164-
if (place == null) {
165-
place = extratags.get("linked_place");
166-
}
167-
if (place != null) {
168-
// take more specific extra tag information
169-
tagKey = "place";
170-
tagValue = place;
171-
}
172-
}
173-
174162
return this;
175163
}
176164

@@ -352,7 +340,7 @@ public String getPostcode() {
352340
return this.postcode;
353341
}
354342

355-
public Map<String, String> getExtratags() {
343+
public Map<String, Object> getExtratags() {
356344
return this.extratags;
357345
}
358346

src/main/java/de/komoot/photon/Server.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import org.jspecify.annotations.NullMarked;
1818
import org.jspecify.annotations.Nullable;
1919
import org.opensearch.client.json.JsonData;
20-
import org.opensearch.client.json.JsonpMapper;
2120
import org.opensearch.client.json.jackson.JacksonJsonpMapper;
2221
import org.opensearch.client.opensearch.OpenSearchClient;
2322
import org.opensearch.client.opensearch._types.HealthStatus;
@@ -73,12 +72,8 @@ public Server(PhotonDBConfig config, boolean create) throws IOException {
7372
.toArray(HttpHost[]::new);
7473
}
7574

76-
final var module = new SimpleModule("PhotonResultDeserializer",
77-
new Version(1, 0, 0, null, null, null));
78-
module.addDeserializer(OpenSearchResult.class, new OpenSearchResultDeserializer());
79-
8075
final var mapper = new JacksonJsonpMapper();
81-
mapper.objectMapper().registerModule(module);
76+
mapper.objectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
8277

8378
final var transport = ApacheHttpClient5TransportBuilder
8479
.builder(hosts)

src/main/java/de/komoot/photon/json/NominatimPlaceDocument.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ void setAddress(@Nullable AddressMap address) {
194194
}
195195

196196
@JsonProperty(DumpFields.PLACE_EXTRA_TAGS)
197-
void setExtratags(@Nullable Map<String, String> extratags) {
197+
void setExtratags(@Nullable Map<String, Object> extratags) {
198198
if (extratags != null) {
199199
//noinspection ConstantValue
200200
extratags.values().removeIf(Objects::isNull);

src/main/java/de/komoot/photon/nominatim/model/PlaceRowMapper.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77

88
import java.sql.ResultSet;
99
import java.sql.SQLException;
10-
import java.util.List;
11-
import java.util.Objects;
12-
import java.util.Set;
10+
import java.util.*;
1311
import java.util.regex.Pattern;
1412

1513
/**
@@ -43,12 +41,23 @@ public PhotonDoc mapRow(ResultSet rs, int rowNum) throws SQLException {
4341
} else if (!CATEGORY_PATTERN.matcher(osmValue).matches()) {
4442
osmValue = "yes";
4543
}
44+
var extratags = dbutils.getMap(rs, "extratags");
45+
String place = extratags.get("place");
46+
if (place == null) {
47+
place = extratags.get("linked_place");
48+
}
49+
if (place != null && CATEGORY_PATTERN.matcher(place).matches()) {
50+
// take more specific extra tag information
51+
osmKey = "place";
52+
osmValue = place;
53+
}
54+
4655
var addressType = AddressType.fromRank(rs.getInt("rank_address"));
4756
PhotonDoc doc = new PhotonDoc(Long.toString(rs.getLong("place_id")),
4857
rs.getString("osm_type"), rs.getLong("osm_id"),
4958
osmKey, osmValue)
5059
.names(NameMap.makeForPlace(dbutils.getMap(rs, "name"), languages))
51-
.extraTags(dbutils.getMap(rs, "extratags"))
60+
.extraTags(Collections.unmodifiableMap(extratags))
5261
.categories(List.of(String.format("osm.%s.%s", osmKey, osmValue)))
5362
.bbox(dbutils.extractGeometry(rs, "bbox"))
5463
.countryCode(rs.getString("country_code"))
Lines changed: 79 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,50 @@
11
package de.komoot.photon.opensearch;
22

3+
import com.fasterxml.jackson.annotation.JsonAnySetter;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
35
import de.komoot.photon.searcher.PhotonResult;
46
import org.jspecify.annotations.NullMarked;
57
import org.jspecify.annotations.Nullable;
68

9+
import java.util.HashMap;
10+
import java.util.List;
711
import java.util.Map;
812

913
@NullMarked
1014
public class OpenSearchResult implements PhotonResult {
11-
private static final String[] NAME_PRECEDENCE = {"default", "housename", "int", "loc", "reg", "alt", "old"};
15+
private static final List<String> KEYS_WITH_LOCALE = List.of(
16+
DocFields.NAME, DocFields.STREET, DocFields.LOCALITY,
17+
DocFields.DISTRICT, DocFields.CITY, DocFields.COUNTY,
18+
DocFields.STATE, DocFields.COUNTRY
19+
);
1220

1321
private double score = 0.0;
14-
private final double @Nullable [] extent;
15-
private final double[] coordinates;
16-
@Nullable private final String geometry;
17-
private final Map<String, Object> infos;
18-
private final Map<String, Map<String, String>> localeTags;
19-
20-
OpenSearchResult(double @Nullable [] extent, double[] coordinates, Map<String, Object> infos, Map<String, Map<String, String>> localeTags, @Nullable String geometry) {
21-
this.extent = extent;
22-
this.coordinates = coordinates;
23-
this.infos = infos;
24-
this.localeTags = localeTags;
25-
this.geometry = geometry;
22+
private double @Nullable [] extent = null;
23+
private double[] coordinates = INVALID_COORDINATES;
24+
private final Map<String, Object> infos = new HashMap<>();
25+
private final Map<String, Map<String, String>> localeTags = new HashMap<>();
26+
27+
28+
record ExtentCoordinates (@JsonProperty("coordinates") double[][] coordinates) {
29+
public double[] getNW() {
30+
return coordinates[0];
31+
}
32+
33+
public double[] getSE() {
34+
return coordinates[1];
35+
}
2636
}
2737

28-
public void setScore(double score) {
29-
this.score = score;
38+
record Point (@JsonProperty("lat") double lat, @JsonProperty("lon") double lon) {}
39+
40+
@Override
41+
public double getScore() {
42+
return this.score;
43+
}
44+
45+
@Override
46+
public void adjustScore(double difference) {
47+
this.score += difference;
3048
}
3149

3250
@Override
@@ -37,41 +55,34 @@ public Object get(String key) {
3755

3856
@Override
3957
@Nullable
40-
public String getLocalised(String key, String language) {
41-
final var map = getMap(key);
58+
public String getLocalised(String key, String language, String... altNames) {
59+
final var map = localeTags.get(key);
4260
if (map == null) return null;
4361

44-
if (map.get(language) != null) {
45-
// language specific field
46-
return map.get(language);
62+
String name = map.get(language);
63+
if (name != null) {
64+
return name;
4765
}
48-
49-
if ("name".equals(key)) {
50-
for (String name : NAME_PRECEDENCE) {
51-
if (map.containsKey(name))
52-
return map.get(name);
53-
}
66+
name = map.get("default");
67+
if (name != null) {
68+
return name;
5469
}
70+
for (var nameKey : altNames) {
71+
name = map.get(nameKey);
72+
if (name != null) {
73+
return name;
74+
}
5575

56-
return map.get("default");
57-
}
76+
}
5877

59-
@Override
60-
@Nullable
61-
public Map<String, String> getMap(String key) {
62-
return localeTags.get(key);
78+
return null;
6379
}
6480

6581
@Override
6682
public double[] getCoordinates() {
6783
return coordinates;
6884
}
6985

70-
@Nullable
71-
public String getGeometry() {
72-
return geometry;
73-
}
74-
7586
@Override
7687
public double @Nullable [] getExtent() {
7788
return extent;
@@ -84,4 +95,35 @@ public Map<String, Object> getRawData() {
8495
"infos", infos,
8596
"localeTags", localeTags);
8697
}
98+
99+
100+
@JsonProperty(DocFields.COORDINATE)
101+
void setCoordinates(Point pt) {
102+
coordinates = new double[]{pt.lon, pt.lat};
103+
}
104+
105+
@JsonProperty(DocFields.EXTENT)
106+
void setExtent(ExtentCoordinates coords) {
107+
final var nw = coords.getNW();
108+
final var se = coords.getSE();
109+
110+
extent = new double[]{nw[0], nw[1], se[0], se[1]};
111+
}
112+
113+
@JsonAnySetter
114+
void setProperties(String key, Object value) {
115+
if (KEYS_WITH_LOCALE.contains(key)) {
116+
if (value instanceof Map<?,?>) {
117+
var names = new HashMap<String, String>();
118+
for (var entry : ((Map<?, ?>) value).entrySet()) {
119+
if (entry.getKey() instanceof String && entry.getValue() instanceof String) {
120+
names.put((String) entry.getKey(), (String) entry.getValue());
121+
}
122+
}
123+
localeTags.put(key, names);
124+
}
125+
} else {
126+
infos.put(key, value);
127+
}
128+
}
87129
}

0 commit comments

Comments
 (0)