Skip to content

Commit 7812e50

Browse files
authored
Merge pull request #382 from simonpoole/update
Improvements to updating code
2 parents 4d77277 + 35ae356 commit 7812e50

File tree

3 files changed

+173
-51
lines changed

3 files changed

+173
-51
lines changed

src/main/java/de/komoot/photon/elasticsearch/Updater.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ public void delete(Long id) {
6161
}
6262

6363
private void updateDocuments() {
64+
if (this.bulkRequest.numberOfActions() == 0) {
65+
log.warn("Update empty");
66+
return;
67+
}
6468
BulkResponse bulkResponse = bulkRequest.execute().actionGet();
6569
if (bulkResponse.hasFailures()) {
6670
log.error("error while bulk update: " + bulkResponse.buildFailureMessage());

src/main/java/de/komoot/photon/nominatim/NominatimConnector.java

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@ boolean isUsefulForIndex() {
4747
}
4848

4949
List<PhotonDoc> getDocsWithHousenumber() {
50-
if (housenumbers == null || housenumbers.isEmpty())
50+
if (housenumbers == null || housenumbers.isEmpty()) {
5151
return ImmutableList.of(doc);
52+
}
5253

5354
List<PhotonDoc> results = new ArrayList<PhotonDoc>(housenumbers.size());
5455
for (Map.Entry<String, Point> e : housenumbers.entrySet()) {
@@ -205,6 +206,8 @@ public NominatimResult mapRow(ResultSet rs, int rowNum) throws SQLException {
205206
}
206207
};
207208
private final String selectColsPlaceX = "place_id, osm_type, osm_id, class, type, name, housenumber, postcode, extratags, ST_Envelope(geometry) AS bbox, parent_place_id, linked_place_id, rank_search, importance, country_code, centroid";
209+
private final String selectColsOsmline = "place_id, osm_id, parent_place_id, startnumber, endnumber, interpolationtype, postcode, country_code, linegeo";
210+
private final String selectColsAddress = "p.place_id, p.osm_type, p.osm_id, p.name, p.class, p.type, p.rank_address, p.admin_level, p.postcode, p.extratags->'place' as place";
208211
private Importer importer;
209212

210213
private Map<String, String> getCountryNames(String countrycode) {
@@ -246,15 +249,20 @@ public void setImporter(Importer importer) {
246249
this.importer = importer;
247250
}
248251

249-
public PhotonDoc getByPlaceId(long placeId) {
250-
return template.queryForObject("SELECT " + selectColsPlaceX + " FROM placex WHERE place_id = ?", new Object[]{placeId}, placeRowMapper).getBaseDoc();
252+
public List<PhotonDoc> getByPlaceId(long placeId) {
253+
NominatimResult result = template.queryForObject("SELECT " + selectColsPlaceX + " FROM placex WHERE place_id = ?", new Object[] { placeId }, placeRowMapper);
254+
completePlace(result.getBaseDoc());
255+
return result.getDocsWithHousenumber();
256+
}
257+
258+
public List<PhotonDoc> getInterpolationsByPlaceId(long placeId) {
259+
NominatimResult result = template.queryForObject("SELECT " + selectColsOsmline + " FROM location_property_osmline WHERE place_id = ?", new Object[] { placeId }, osmlineRowMapper);
260+
completePlace(result.getBaseDoc());
261+
return result.getDocsWithHousenumber();
251262
}
252263

253264
List<AddressRow> getAddresses(PhotonDoc doc) {
254-
long placeId = doc.getPlaceId();
255-
if (doc.getRankSearch() > 28)
256-
placeId = doc.getParentPlaceId();
257-
return template.query("SELECT p.place_id, p.osm_type, p.osm_id, p.name, p.class, p.type, p.rank_address, p.admin_level, p.postcode, p.extratags->'place' as place FROM placex p, place_addressline pa WHERE p.place_id = pa.address_place_id and pa.place_id = ? and pa.cached_rank_address > 4 and pa.address_place_id != ? and pa.isaddress order by rank_address desc,fromarea desc,distance asc,rank_search desc", new Object[]{placeId, doc.getPlaceId()}, new RowMapper<AddressRow>() {
265+
RowMapper<AddressRow> rowMapper = new RowMapper<AddressRow>() {
258266
@Override
259267
public AddressRow mapRow(ResultSet rs, int rowNum) throws SQLException {
260268
Integer adminLevel = rs.getInt("admin_level");
@@ -274,7 +282,19 @@ public AddressRow mapRow(ResultSet rs, int rowNum) throws SQLException {
274282
rs.getLong("osm_id")
275283
);
276284
}
277-
});
285+
};
286+
287+
boolean isPoi = doc.getRankSearch() > 28;
288+
long placeId = (isPoi) ? doc.getParentPlaceId() : doc.getPlaceId();
289+
290+
List<AddressRow> terms = template.query("SELECT " + selectColsAddress + " FROM placex p, place_addressline pa WHERE p.place_id = pa.address_place_id and pa.place_id = ? and pa.cached_rank_address > 4 and pa.address_place_id != ? and pa.isaddress order by rank_address desc,fromarea desc,distance asc,rank_search desc", new Object[]{placeId, placeId}, rowMapper);
291+
292+
if (isPoi) {
293+
// need to add the term for the parent place ID itself
294+
terms.addAll(0, template.query("SELECT " + selectColsAddress + " FROM placex p WHERE p.place_id = ?", new Object[]{placeId}, rowMapper));
295+
}
296+
297+
return terms;
278298
}
279299

280300
private static final PhotonDoc FINAL_DOCUMENT = new PhotonDoc(0, null, 0, null, null, null, null, null, null, 0, 0, null, null, 0, 0);

src/main/java/de/komoot/photon/nominatim/NominatimUpdater.java

Lines changed: 141 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.sql.SQLException;
1313
import java.util.List;
1414
import java.util.Map;
15+
import java.util.concurrent.locks.ReentrantLock;
1516

1617
/**
1718
* Nominatim update logic
@@ -21,69 +22,166 @@
2122

2223
public class NominatimUpdater {
2324
private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(NominatimUpdater.class);
24-
private final Integer minRank = 1;
25-
private final Integer maxRank = 30;
26-
private final JdbcTemplate template;
25+
26+
private static final int CREATE = 1;
27+
private static final int UPDATE = 2;
28+
private static final int DELETE = 100;
29+
30+
private static final int MIN_RANK = 1;
31+
private static final int MAX_RANK = 30;
32+
33+
private final JdbcTemplate template;
2734
private final NominatimConnector exporter;
2835

2936
private Updater updater;
3037

38+
/**
39+
* when updating lockout other threads
40+
*/
41+
private ReentrantLock updateLock = new ReentrantLock();
42+
3143
public void setUpdater(Updater updater) {
3244
this.updater = updater;
3345
}
3446

3547
public void update() {
36-
for (Integer rank = this.minRank; rank <= this.maxRank; rank++) {
37-
LOGGER.info(String.format("Starting rank %d", rank));
38-
for (Map<String, Object> sector : getIndexSectors(rank))
39-
for (UpdateRow place : getIndexSectorPlaces(rank, (Integer) sector.get("geometry_sector"))) {
40-
41-
template.update("update placex set indexed_status = 0 where place_id = ?", place.getPlaceId());
42-
final PhotonDoc updatedDoc = exporter.getByPlaceId(place.getPlaceId());
43-
44-
switch (place.getIndexdStatus()) {
45-
case 1:
46-
if (updatedDoc.isUsefulForIndex())
47-
updater.create(updatedDoc);
48-
break;
49-
case 2:
50-
if (!updatedDoc.isUsefulForIndex())
51-
updater.delete(place.getPlaceId());
52-
53-
updater.updateOrCreate(updatedDoc);
54-
break;
55-
case 100:
56-
updater.delete(place.getPlaceId());
57-
break;
58-
default:
59-
LOGGER.error(String.format("Unknown index status %d", place.getIndexdStatus()));
60-
break;
48+
if (updateLock.tryLock()) {
49+
try {
50+
int updatedPlaces = 0;
51+
int deletedPlaces = 0;
52+
for (int rank = MIN_RANK; rank <= MAX_RANK; rank++) {
53+
LOGGER.info(String.format("Starting rank %d", rank));
54+
for (Map<String, Object> sector : getIndexSectors(rank)) {
55+
for (UpdateRow place : getIndexSectorPlaces(rank, (Integer) sector.get("geometry_sector"))) {
56+
long placeId = place.getPlaceId();
57+
template.update("update placex set indexed_status = 0 where place_id = ?;", placeId);
58+
59+
Integer indexedStatus = place.getIndexdStatus();
60+
if (indexedStatus == DELETE || (indexedStatus == UPDATE && rank == MAX_RANK)) {
61+
updater.delete(placeId);
62+
if (indexedStatus == DELETE) {
63+
deletedPlaces++;
64+
continue;
65+
}
66+
indexedStatus = CREATE; // always create
67+
}
68+
updatedPlaces++;
69+
70+
final List<PhotonDoc> updatedDocs = exporter.getByPlaceId(place.getPlaceId());
71+
boolean wasUseful = false;
72+
for (PhotonDoc updatedDoc : updatedDocs) {
73+
switch (indexedStatus) {
74+
case CREATE:
75+
if (updatedDoc.isUsefulForIndex()) {
76+
updater.create(updatedDoc);
77+
}
78+
break;
79+
case UPDATE:
80+
if (updatedDoc.isUsefulForIndex()) {
81+
updater.updateOrCreate(updatedDoc);
82+
wasUseful = true;
83+
}
84+
break;
85+
default:
86+
LOGGER.error(String.format("Unknown index status %d", indexedStatus));
87+
break;
88+
}
89+
}
90+
if (indexedStatus == UPDATE && !wasUseful) {
91+
// only true when rank != 30
92+
// if no documents for the place id exist this will likely cause moaning
93+
updater.delete(placeId);
94+
updatedPlaces--;
95+
}
96+
}
6197
}
6298
}
63-
}
6499

65-
updater.finish();
100+
LOGGER.info(String.format("%d places created or updated, %d deleted", updatedPlaces, deletedPlaces));
101+
102+
// update documents generated from address interpolations
103+
// .isUsefulForIndex() should always return true for documents
104+
// created from interpolations so no need to check them
105+
LOGGER.info("Starting interpolations");
106+
int updatedInterpolations = 0;
107+
int deletedInterpolations = 0;
108+
int interpolationDocuments = 0;
109+
for (Map<String, Object> sector : template.queryForList(
110+
"select geometry_sector,count(*) from location_property_osmline where indexed_status > 0 group by geometry_sector order by geometry_sector;")) {
111+
for (UpdateRow place : getIndexSectorInterpolations((Integer) sector.get("geometry_sector"))) {
112+
long placeId = place.getPlaceId();
113+
template.update("update location_property_osmline set indexed_status = 0 where place_id = ?;", placeId);
114+
115+
Integer indexedStatus = place.getIndexdStatus();
116+
if (indexedStatus != CREATE) {
117+
updater.delete(placeId);
118+
if (indexedStatus == DELETE) {
119+
deletedInterpolations++;
120+
continue;
121+
}
122+
}
123+
updatedInterpolations++;
124+
125+
final List<PhotonDoc> updatedDocs = exporter.getInterpolationsByPlaceId(place.getPlaceId());
126+
for (PhotonDoc updatedDoc : updatedDocs) {
127+
updater.create(updatedDoc);
128+
interpolationDocuments++;
129+
}
130+
}
131+
}
132+
LOGGER.info(String.format("%d interpolations created or updated, %d deleted, %d documents added or updated", updatedInterpolations,
133+
deletedInterpolations, interpolationDocuments));
134+
updater.finish();
135+
template.update("update import_status set indexed=true;"); // indicate that we are finished
136+
137+
LOGGER.info("Finished updating");
138+
} finally {
139+
updateLock.unlock();
140+
}
141+
} else {
142+
LOGGER.info("Update already in progress");
143+
}
66144
}
67145

68146
private List<Map<String, Object>> getIndexSectors(Integer rank) {
69-
return template.queryForList("select geometry_sector,count(*) from placex where rank_search = ? " +
70-
"and indexed_status > 0 group by geometry_sector order by geometry_sector;", rank);
147+
return template.queryForList("select geometry_sector,count(*) from placex where rank_search = ? "
148+
+ "and indexed_status > 0 group by geometry_sector order by geometry_sector;", rank);
71149
}
72150

73151
private List<UpdateRow> getIndexSectorPlaces(Integer rank, Integer geometrySector) {
74-
return template.query("select place_id, indexed_status from placex where rank_search = ?" +
75-
" and geometry_sector = ? and indexed_status > 0;", new Object[]{rank, geometrySector}, new RowMapper<UpdateRow>() {
76-
@Override
77-
public UpdateRow mapRow(ResultSet rs, int rowNum) throws SQLException {
78-
UpdateRow updateRow = new UpdateRow();
79-
updateRow.setPlaceId(rs.getLong("place_id"));
80-
updateRow.setIndexdStatus(rs.getInt("indexed_status"));
81-
return updateRow;
82-
}
83-
});
152+
return template.query("select place_id, indexed_status from placex where rank_search = ?" + " and geometry_sector = ? and indexed_status > 0;",
153+
new Object[] { rank, geometrySector }, new RowMapper<UpdateRow>() {
154+
@Override
155+
public UpdateRow mapRow(ResultSet rs, int rowNum) throws SQLException {
156+
UpdateRow updateRow = new UpdateRow();
157+
updateRow.setPlaceId(rs.getLong("place_id"));
158+
updateRow.setIndexdStatus(rs.getInt("indexed_status"));
159+
return updateRow;
160+
}
161+
});
162+
}
163+
164+
private List<UpdateRow> getIndexSectorInterpolations(Integer geometrySector) {
165+
return template.query("select place_id, indexed_status from location_property_osmline where geometry_sector = ? and indexed_status > 0;",
166+
new Object[] { geometrySector }, new RowMapper<UpdateRow>() {
167+
@Override
168+
public UpdateRow mapRow(ResultSet rs, int rowNum) throws SQLException {
169+
UpdateRow updateRow = new UpdateRow();
170+
updateRow.setPlaceId(rs.getLong("place_id"));
171+
updateRow.setIndexdStatus(rs.getInt("indexed_status"));
172+
return updateRow;
173+
}
174+
});
84175
}
85176

86177
/**
178+
* Creates a new instance
179+
*
180+
* @param host Nominatim database host
181+
* @param port Nominatim database port
182+
* @param database Nominatim database name
183+
* @param username Nominatim database username
184+
* @param password Nominatim database password
87185
*/
88186
public NominatimUpdater(String host, int port, String database, String username, String password) {
89187
BasicDataSource dataSource = new BasicDataSource();
@@ -92,7 +190,7 @@ public NominatimUpdater(String host, int port, String database, String username,
92190
dataSource.setUsername(username);
93191
dataSource.setPassword(password);
94192
dataSource.setDriverClassName(JtsWrapper.class.getCanonicalName());
95-
dataSource.setDefaultAutoCommit(false);
193+
dataSource.setDefaultAutoCommit(true);
96194

97195
exporter = new NominatimConnector(host, port, database, username, password);
98196
template = new JdbcTemplate(dataSource);

0 commit comments

Comments
 (0)