Я работаю с Lucene версии 8.4.1 и получил несколько вопросов о пространственной индексации. Речь идет о производительности, а затем о пространственном поиске. Мои тестовые данные около 10000 полигонов. Это небольшой набор данных.
Прежде всего, мои настройки:
// JtsSpaticalContext is needed to index polygons
this.ctx = JtsSpatialContext.GEO;
SpatialPrefixTree tree = new GeohashPrefixTree(this.ctx, MAX_LEVEL);
this.strategy = new RecursivePrefixTreeStrategy(tree, GEOMETRY_FIELDNAME);
this.shapeReader = this.ctx.getFormats().getWktReader();
// Creating the path for lucene index files
Path path = Paths.get(INDEX_FOLDER);
this.dir = SimpleFSDirectory.open(path);
// preparing IndexWriter
IndexWriterConfig config = new IndexWriterConfig(new StandardAnalyzer());
config.setOpenMode(OpenMode.CREATE);
config.setRAMBufferSizeMB(256.0);
config.setUseCompoundFile(false);
config.setMaxBufferedDocs(IndexWriterConfig.DISABLE_AUTO_FLUSH);
LogMergePolicy policy = new LogDocMergePolicy();
policy.setMergeFactor(15);
config.setMergePolicy(policy);
this.indexWriter = new IndexWriter(dir, config);
Как вы можете видеть, я использую JtsSpatialContext для индексации моих пространственных данных. Конфиг для меня все еще волшебный c, это консульство дало мне лучшие результаты. MAX_LEVEL для GeohashPrefixTree установлено в 11. Также: this.shapeReader = this.ctx.getFormats (). GetWktReader используется для избавления от Устаревший предупреждение, которое отображается, когда я использую ctx.readFromWkt . Я наблюдал за SpatialExample. java от официального репо Lucene Github Github Repo SpatialExample
Теперь, как я уже сказал, я хочу проиндексировать ~ 10000 полигонов, которые находятся в Мой случай использования небольшой набор данных. У меня есть два подхода для индексации этих данных, отличающиеся на CaseA и CaseB
Вот мой логик c, как я добавляю эти полигоны в свой индекс:
// Start Case A
List<String> testDataCaseA = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
testDataCaseA.add("POLYGON((9.0842201 48.80324419974113,9.084344 48.803237199741126,9.0843574 48.80333909974109,9.0842334 48.8033461997411,9.0842201 48.80324419974113))");
}
long startCaseA = System.nanoTime();
testDataCaseA.parallelStream().forEach(current -> {
try {
this.indexWriter.addDocument(createDocumentCaseA(current));
} catch (InvalidShapeException | IOException | java.text.ParseException e) {
logger.error(e.toString());
}
});
double elapsedTimeCaseA = (System.nanoTime() - startCaseA) / 1000000;
logger.trace("Elapsed Time: " + elapsedTimeCaseA + "ms");
// End Case A
// Deleting the index
this.indexWriter.deleteAll();
// Start Case B
List<String> testDataCaseB = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
testDataCaseB.add("{\"type\":\"Polygon\",\"coordinates\":[[[9.0842201,48.80324419974113],[9.084344,48.803237199741126],[9.0843574,48.80333909974109],[9.0842334,48.8033461997411],[9.0842201,48.80324419974113]]]}");
}
long startCaseB = System.nanoTime();
testDataCaseB.parallelStream().forEach(current -> {
try {
this.indexWriter.addDocument(createDocumentCaseB(current));
} catch (java.text.ParseException | IOException e) {
logger.error(e.toString());
}
});
double elapsedTimeCaseB = (System.nanoTime() - startCaseB) / 1000000;
logger.trace("Elapsed Time: " + elapsedTimeCaseB + "ms");
// End Case B
А вот методы createDocumentCaseA и createDocumentCaseB
private Document createDocumentCaseA(String geom) throws java.text.ParseException, InvalidShapeException, IOException {
Document doc = new Document();
for (Field f : strategy.createIndexableFields(this.shapeReader.read(geom))) {
doc.add(f);
}
return doc;
}
private Document createDocumentCaseB(String geom) throws java.text.ParseException {
Document doc = new Document();
for (Polygon poly : Polygon.fromGeoJSON(geom)) {
for (Field f : LatLonShape.createIndexableFields(GEOMETRY_FIELDNAME, poly)) {
doc.add(f);
}
}
return doc;
}
Разница между этими двумя вариантами поразительна:
Истекшее время случая A: 41522,0 мс
Истекшее время случая B: 168,0 мс
Ну, я подумал: "Хм, хорошо, тогда я просто выбираю случай B и все в порядке". Но моя проблема на «понятном уровне»: каков «правильный» способ сделать это? И еще: если я использую пространственный поиск, в CaseA я получил метод strategy.makeQuery (SpatialArgs) , в CaseB мне нужно использовать LatLonShape.createXYQuery (someStuff)
Какой способ выбрать? Я что-то упустил в документах от Lucene?