Skip to content

Commit

Permalink
[ issue #14 ] SPARQL Integration suite works on SOLR too!
Browse files Browse the repository at this point in the history
  • Loading branch information
agazzarini committed Aug 28, 2014
1 parent 3defee6 commit e03bf3f
Show file tree
Hide file tree
Showing 14 changed files with 330 additions and 87 deletions.
1 change: 0 additions & 1 deletion jena-nosql-binding/jena-nosql-binding-solr/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
<version>${solr.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.gazzax.labs.jena.nosql.solr;

public interface Field {
String ID = "id";
String S = "s";
String P = "p";
String O = "o";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package org.gazzax.labs.jena.nosql.solr;

import java.util.Iterator;

import org.gazzax.labs.jena.nosql.fwk.StorageLayerException;
import org.gazzax.labs.jena.nosql.fwk.dictionary.TopLevelDictionary;
import org.gazzax.labs.jena.nosql.fwk.factory.StorageLayerFactory;

import com.hp.hpl.jena.graph.Node;
import com.hp.hpl.jena.graph.Triple;
import com.hp.hpl.jena.sparql.core.Quad;

/**
* A NullObject dictionary that, as the name suggests, does nothing.
*
* @author Andrea Gazzarini
* @since 1.0
*/
class NoOpDictionary implements TopLevelDictionary {

@Override
public void close() {
// Nothing to be done here...
}

@Override
public byte[] getID(Node node, boolean p) throws StorageLayerException {
// Nothing to be done here...
return null;
}

@Override
public Node getValue(byte[] id, boolean p) throws StorageLayerException {
// Nothing to be done here...
return null;
}

@Override
public void removeValue(Node value, boolean p) throws StorageLayerException {
// Nothing to be done here...
}

@Override
public String getName() {
// Nothing to be done here...
return null;
}

@Override
public void initialise(final StorageLayerFactory factory) {
// Nothing to be done here...
}

@Override
public byte[][] asIdentifiers(final Node s, final Node p, final Node o) {
// Nothing to be done here...
return null;
}

@Override
public byte[][] asIdentifiers(final Node s, final Node p, final Node o, final Node c) {
// Nothing to be done here...
return null;
}

@Override
public Triple asTriple(final byte[] s, final byte[] p, final byte[] o) {
// Nothing to be done here...
return null;
}

@Override
public Quad asQuad(final byte[] s, final byte[] p, final byte[] o, final byte[] c) {
// Nothing to be done here...
return null;
}

@Override
public boolean isBNode(final byte[] id) {
// Nothing to be done here...
return false;
}

@Override
public boolean isLiteral(final byte[] id) {
// Nothing to be done here...
return false;
}

@Override
public boolean isResource(final byte[] id) {
// Nothing to be done here...
return false;
}

@Override
public Iterator<byte[][]> asTripleIdentifiersIterator(final Iterator<Triple> triples) {
// Nothing to be done here...
return null;
}

@Override
public Iterator<byte[][]> asQuadIdentifiersIterator(final Iterator<Quad> quads) {
// Nothing to be done here...
return null;
}

@Override
public Iterator<Triple> asTripleIterator(final Iterator<byte[][]> identifiers) {
// Nothing to be done here...
return null;
}

@Override
public Iterator<Quad> asQuadIterator(final Iterator<byte[][]> quads) {
// Nothing to be done here...
return null;
}

@Override
public byte[] compose(final byte[] id1, final byte[] id2) {
// Nothing to be done here...
return null;
}

@Override
public byte[] compose(final byte[] id1, final byte[] id2, final byte[] id3) {
// Nothing to be done here...
return null;
}

@Override
public byte[][] decompose(final byte[] compositeId) {
// Nothing to be done here...
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
* @since 1.0
*/
public class SolrStorageLayerFactory extends StorageLayerFactory {
private final TopLevelDictionary dictionary = new NoOpDictionary();
private SolrServer solr;

@Override
Expand Down Expand Up @@ -65,7 +66,7 @@ public TripleIndexDAO<Triple, TripleMatch> getTripleIndexDAO() {

@Override
public TopLevelDictionary getDictionary() {
throw new UnsupportedOperationException();
return dictionary;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package org.gazzax.labs.jena.nosql.solr.dao;

import java.util.Iterator;

import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
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.params.CursorMarkParams;
import org.gazzax.labs.jena.nosql.fwk.util.NTriples;
import org.gazzax.labs.jena.nosql.solr.Field;

import com.google.common.collect.UnmodifiableIterator;
import com.hp.hpl.jena.graph.Triple;

/**
* An iterator over SOLR results that uses the built-in Deep Paging strategy.
* Internally it uses other iterators to represents each iteration state.
*
* @see http://solr.pl/en/2014/03/10/solr-4-7-efficient-deep-paging
* @see http://heliosearch.org/solr/paging-and-deep-paging
* @see <a href="http://en.wikipedia.org/wiki/Finite-state_machine">http://en.wikipedia.org/wiki/Finite-state_machine</a>
* @author Andrea Gazzarini
* @since 1.0
*/
public class SolrDeepPagingIterator extends UnmodifiableIterator<Triple> {

private final SolrServer solr;
private final SolrQuery query;
private SolrDocumentList page;

private String nextCursorMark;
private String sentCursorMark;

/**
* Iteration state: we need to (re)execute a query.
* This could be needed the very first time we start iteration and each time the current result
* page has been consumed.
*/
private final Iterator<Triple> executeQuery = new UnmodifiableIterator<Triple>() {
@Override
public boolean hasNext() {
try {
final QueryResponse response = solr.query(query);
nextCursorMark = response.getNextCursorMark();
page = response.getResults();
return page.getNumFound() > 0;
} catch (final Exception exception) {
throw new RuntimeException(exception);
}
}

@Override
public Triple next() {
currentState = iterateOverCurrentPage;
return currentState.next();
}
};

/**
* Iteration state: query has been executed and now it's time to iterate over results.
*/
private final Iterator<Triple> iterateOverCurrentPage = new UnmodifiableIterator<Triple>() {
Iterator<SolrDocument> iterator;

@Override
public boolean hasNext() {
if (iterator().hasNext()) {
return true;
} else {
currentState = checkForIterationCompleteness;
return currentState.hasNext();
}
}

@Override
public Triple next() {
final SolrDocument document = iterator().next();
return Triple.create(
NTriples.asURIorBlankNode((String) document.getFieldValue(Field.S)),
NTriples.asURI((String) document.getFieldValue(Field.P)),
NTriples.asNode((String) document.getFieldValue(Field.O)));
}

Iterator<SolrDocument> iterator() {
if (iterator == null) {
iterator = page.iterator();
}
return iterator;

}
};

/**
* Iteration state: once a page has been consumed we need to determine if another query should be issued or not.
*/
private final Iterator<Triple> checkForIterationCompleteness = new UnmodifiableIterator<Triple>() {
@Override
public boolean hasNext() {
return !(page.size() < query.getRows() || sentCursorMark.equals(nextCursorMark));
}

@Override
public Triple next() {
query.set(CursorMarkParams.CURSOR_MARK_PARAM, nextCursorMark);
currentState = executeQuery;
return currentState.next();
}
};

private Iterator<Triple> currentState = executeQuery;

/**
* Builds a new iterator with the given data.
*
* @param solr the SOLR facade.
* @param query the query that will be submitted.
*/
public SolrDeepPagingIterator(final SolrServer solr, final SolrQuery query) {
this.solr = solr;
this.query = query;
this.sentCursorMark = CursorMarkParams.CURSOR_MARK_START;
this.query.set(CursorMarkParams.CURSOR_MARK_PARAM, CursorMarkParams.CURSOR_MARK_START);
}

@Override
public boolean hasNext() {
return currentState.hasNext();
}

@Override
public Triple next() {
return currentState.next();
}
}
Loading

0 comments on commit e03bf3f

Please sign in to comment.