com.orientechnologies.spatial.engine.OLuceneLegacySpatialIndexEngine Maven / Gradle / Ivy
Show all versions of orientdb-lucene Show documentation
/*
* Copyright 2010-2016 OrientDB LTD (http://orientdb.com)
*
* 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.
*
* For more information: http://www.orientdb.com
*/
package com.orientechnologies.spatial.engine;
import static com.orientechnologies.lucene.builder.OLuceneQueryBuilder.EMPTY_METADATA;
import com.orientechnologies.lucene.collections.OLuceneResultSet;
import com.orientechnologies.lucene.query.OLuceneQueryContext;
import com.orientechnologies.lucene.tx.OLuceneTxChanges;
import com.orientechnologies.orient.core.command.OCommandContext;
import com.orientechnologies.orient.core.db.record.OIdentifiable;
import com.orientechnologies.orient.core.id.OContextualRecordId;
import com.orientechnologies.orient.core.id.ORID;
import com.orientechnologies.orient.core.index.OCompositeKey;
import com.orientechnologies.orient.core.index.OIndexDefinition;
import com.orientechnologies.orient.core.index.OIndexEngineException;
import com.orientechnologies.orient.core.index.OIndexKeyUpdater;
import com.orientechnologies.orient.core.index.engine.IndexEngineValidator;
import com.orientechnologies.orient.core.metadata.schema.OType;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.storage.OStorage;
import com.orientechnologies.orient.core.storage.impl.local.paginated.atomicoperations.OAtomicOperation;
import com.orientechnologies.spatial.collections.OSpatialCompositeKey;
import com.orientechnologies.spatial.query.OSpatialQueryContext;
import com.orientechnologies.spatial.shape.OShapeBuilder;
import com.orientechnologies.spatial.shape.legacy.OShapeBuilderLegacy;
import com.orientechnologies.spatial.shape.legacy.OShapeBuilderLegacyImpl;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.apache.lucene.document.Document;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.DoubleValuesSource;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Sort;
import org.apache.lucene.spatial.SpatialStrategy;
import org.apache.lucene.spatial.prefix.RecursivePrefixTreeStrategy;
import org.apache.lucene.spatial.prefix.tree.GeohashPrefixTree;
import org.apache.lucene.spatial.query.SpatialArgs;
import org.apache.lucene.spatial.query.SpatialOperation;
import org.locationtech.spatial4j.distance.DistanceUtils;
import org.locationtech.spatial4j.shape.Point;
import org.locationtech.spatial4j.shape.Shape;
/** Created by Enrico Risa on 26/09/15. */
public class OLuceneLegacySpatialIndexEngine extends OLuceneSpatialIndexEngineAbstract {
private final OShapeBuilderLegacy legacyBuilder = OShapeBuilderLegacyImpl.INSTANCE;
public OLuceneLegacySpatialIndexEngine(
OStorage storage, String indexName, int id, OShapeBuilder factory) {
super(storage, indexName, id, factory);
}
private Set legacySearch(Object key, OLuceneTxChanges changes) throws IOException {
if (key instanceof OSpatialCompositeKey) {
final OSpatialCompositeKey newKey = (OSpatialCompositeKey) key;
final SpatialOperation strategy =
newKey.getOperation() != null ? newKey.getOperation() : SpatialOperation.Intersects;
if (SpatialOperation.Intersects.equals(strategy))
return searchIntersect(newKey, newKey.getMaxDistance(), newKey.getContext(), changes);
else if (SpatialOperation.IsWithin.equals(strategy))
return searchWithin(newKey, newKey.getContext(), changes);
} else if (key instanceof OCompositeKey) {
return searchIntersect((OCompositeKey) key, 0, null, changes);
}
throw new OIndexEngineException("Unknown key" + key, null);
}
private Set searchIntersect(
OCompositeKey key, double distance, OCommandContext context, OLuceneTxChanges changes)
throws IOException {
double lat = (Double) OType.convert(key.getKeys().get(0), Double.class);
double lng = (Double) OType.convert(key.getKeys().get(1), Double.class);
SpatialOperation operation = SpatialOperation.Intersects;
@SuppressWarnings("deprecation")
Point p = ctx.makePoint(lng, lat);
@SuppressWarnings("deprecation")
SpatialArgs args =
new SpatialArgs(
operation,
ctx.makeCircle(
lng,
lat,
DistanceUtils.dist2Degrees(distance, DistanceUtils.EARTH_MEAN_RADIUS_KM)));
Query filterQuery = strategy.makeQuery(args);
IndexSearcher searcher = searcher();
DoubleValuesSource valueSource = strategy.makeDistanceValueSource(p);
Sort distSort = new Sort(valueSource.getSortField(false)).rewrite(searcher);
BooleanQuery q =
new BooleanQuery.Builder()
.add(filterQuery, BooleanClause.Occur.MUST)
.add(new MatchAllDocsQuery(), BooleanClause.Occur.SHOULD)
.build();
OLuceneQueryContext queryContext =
new OSpatialQueryContext(context, searcher, q, Arrays.asList(distSort.getSort()))
.setSpatialArgs(args)
.withChanges(changes);
return new OLuceneResultSet(this, queryContext, EMPTY_METADATA);
}
private Set searchWithin(
OSpatialCompositeKey key, OCommandContext context, OLuceneTxChanges changes) {
Shape shape = legacyBuilder.makeShape(key, ctx);
if (shape == null) return null;
SpatialArgs args = new SpatialArgs(SpatialOperation.IsWithin, shape);
IndexSearcher searcher = searcher();
Query filterQuery = strategy.makeQuery(args);
BooleanQuery query =
new BooleanQuery.Builder()
.add(filterQuery, BooleanClause.Occur.MUST)
.add(new MatchAllDocsQuery(), BooleanClause.Occur.SHOULD)
.build();
OLuceneQueryContext queryContext =
new OSpatialQueryContext(context, searcher, query).withChanges(changes);
return new OLuceneResultSet(this, queryContext, EMPTY_METADATA);
}
@Override
public void onRecordAddedToResultSet(
OLuceneQueryContext queryContext,
OContextualRecordId recordId,
Document doc,
ScoreDoc score) {
OSpatialQueryContext spatialContext = (OSpatialQueryContext) queryContext;
if (spatialContext.spatialArgs != null) {
@SuppressWarnings("deprecation")
Point docPoint = (Point) ctx.readShape(doc.get(strategy.getFieldName()));
double docDistDEG =
ctx.getDistCalc().distance(spatialContext.spatialArgs.getShape().getCenter(), docPoint);
final double docDistInKM =
DistanceUtils.degrees2Dist(docDistDEG, DistanceUtils.EARTH_EQUATORIAL_RADIUS_KM);
Map data = new HashMap();
data.put("distance", docDistInKM);
recordId.setContext(data);
}
}
@Override
public Set getInTx(Object key, OLuceneTxChanges changes) {
try {
updateLastAccess();
openIfClosed();
return legacySearch(key, changes);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
public Object get(Object key) {
return getInTx(key, null);
}
@Override
public void put(OAtomicOperation atomicOperation, Object key, Object value) {
if (key instanceof OCompositeKey) {
updateLastAccess();
openIfClosed();
OCompositeKey compositeKey = (OCompositeKey) key;
addDocument(
newGeoDocument(
(OIdentifiable) value,
legacyBuilder.makeShape(compositeKey, ctx),
((OCompositeKey) key).toDocument()));
}
}
@Override
public void update(
OAtomicOperation atomicOperation, Object key, OIndexKeyUpdater