org.apache.jena.query.spatial.SpatialIndexSolr Maven / Gradle / Ivy
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.jena.query.spatial;
import java.util.ArrayList ;
import java.util.List ;
import org.apache.jena.graph.Node ;
import org.apache.jena.sparql.util.NodeFactoryExtra ;
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.prefix.tree.SpatialPrefixTree ;
import org.apache.lucene.spatial.query.SpatialOperation ;
import org.apache.solr.client.solrj.SolrQuery ;
import org.apache.solr.client.solrj.SolrServer ;
import org.apache.solr.client.solrj.SolrServerException ;
import org.apache.solr.client.solrj.response.QueryResponse ;
import org.apache.solr.common.SolrDocument ;
import org.apache.solr.common.SolrDocumentList ;
import org.apache.solr.common.SolrInputDocument ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
import com.spatial4j.core.shape.Shape ;
public class SpatialIndexSolr implements SpatialIndex {
private static Logger log = LoggerFactory.getLogger(SpatialIndexSolr.class);
private final SolrServer solrServer;
private EntityDefinition docDef;
private SpatialPrefixTree grid;
/**
* The Lucene spatial {@link SpatialStrategy} encapsulates an approach to
* indexing and searching shapes, and providing distance values for them.
* It's a simple API to unify different approaches. You might use more than
* one strategy for a shape as each strategy has its strengths and
* weaknesses.
*
* Note that these are initialized with a field name.
*/
private SpatialStrategy strategy;
public SpatialIndexSolr(SolrServer server, EntityDefinition def) {
this.solrServer = server;
this.docDef = def;
int maxLevels = 11;// results in sub-meter precision for geohash
// This can also be constructed from SpatialPrefixTreeFactory
grid = new GeohashPrefixTree(SpatialQuery.ctx, maxLevels);
this.strategy = new RecursivePrefixTreeStrategy(grid, def.getGeoField());
}
@Override
public void startIndexing() {
}
@Override
public void finishIndexing() {
try {
solrServer.commit();
} catch (Exception ex) {
exception(ex);
}
}
@Override
public void abortIndexing() {
try {
solrServer.rollback();
} catch (Exception ex) {
exception(ex);
}
}
@Override
public void close() {
if (solrServer != null)
solrServer.shutdown();
}
@Override
public void add(String entityURI, Shape... shapes) {
// log.info("Add entity: "+entityURI) ;
try {
SolrInputDocument doc = solrDoc(entityURI, shapes);
solrServer.add(doc);
} catch (Exception e) {
exception(e);
}
}
@SuppressWarnings("deprecation")
private SolrInputDocument solrDoc(String entityURI, Shape... shapes) {
SolrInputDocument doc = new SolrInputDocument();
doc.addField(docDef.getEntityField(), entityURI);
if (shapes.length != 1) {
throw new SpatialIndexException(
"Solr spatial only supports indexing one shape a time, but provided: "
+ shapes.length + " shapes.");
}
doc.addField(docDef.getGeoField(), SpatialQuery.ctx.toString(shapes[0]));
return doc;
}
@Override
public List query(Shape shape, int limit, SpatialOperation operation) {
SolrDocumentList solrResults = solrQuery(shape, limit, operation);
List results = new ArrayList<>();
for (SolrDocument sd : solrResults) {
String str = (String) sd.getFieldValue(docDef.getEntityField());
Node n = SpatialQueryFuncs.stringToNode(str) ;
results.add(n) ;
}
if (limit > 0 && results.size() > limit)
results = results.subList(0, limit);
return results;
}
@SuppressWarnings("deprecation")
private SolrDocumentList solrQuery(Shape shape, int limit,
SpatialOperation operation) {
SolrQuery sq = new SolrQuery();
sq.setQuery("*:*");
sq.setFilterQueries(docDef.getGeoField() + ":\"" + operation.toString()
+ "(" + SpatialQuery.ctx.toString(shape) + ") distErrPct=0\"");
//System.out.println("SolrQuery: " +sq.toString());
try {
QueryResponse rsp = solrServer.query(sq);
SolrDocumentList docs = rsp.getResults();
return docs;
} catch (SolrServerException e) {
exception(e);
return null;
}
}
@Override
public EntityDefinition getDocDef() {
return docDef;
}
private Node entryToNode(String v) {
// TEMP
return NodeFactoryExtra.createLiteralNode(v, null, null);
}
public SolrServer getServer() {
return solrServer;
}
private static Void exception(Exception ex) {
throw new SpatialIndexException(ex);
}
}