Skip to content
This repository has been archived by the owner on Oct 12, 2021. It is now read-only.

Commit

Permalink
Accept a searchTerm in the getResources method (#51)
Browse files Browse the repository at this point in the history
* getResources method accepts a searchTerm, that translates to a simple
sparql filter.
* tests for getResources() that returns a Jena model.
* Update free-text search to work with more than String literals.
Unit tests working.
  • Loading branch information
jadelkhoury authored and berezovskyi committed Feb 16, 2019
1 parent 3723894 commit 5154831
Show file tree
Hide file tree
Showing 9 changed files with 537 additions and 53 deletions.
44 changes: 41 additions & 3 deletions src/store-core/src/main/java/org/eclipse/lyo/store/Store.java
Expand Up @@ -149,22 +149,60 @@ <T extends IResource> List<T> getResources(URI namedGraphUri, final Class<T> cla
<T extends IResource> List<T> getResources(URI namedGraphUri, Class<T> clazz, int limit,
int offset) throws StoreAccessException, ModelUnmarshallingException;

/**
* Alternative to {@link Store#getResources(URI, Class)} with paging on the OSLC resource level.
*
* @param namedGraphUri URI of a named graph under which resources were stored
* @param clazz class of the resources being retrieved
* @param prefixes defines the prefixes for prefixed names that appear in the oslc.where query parameter.
* @param where filters the member list, keeping only those member resources that satisfy the boolean test on the member resource properties. (See oslc.where at https://tools.oasis-open.org/version-control/browse/wsvn/oslc-core/trunk/specs/oslc-query.html)
* @param searchTerms score each member resource using a full text search on it text-valued properties. (See oslc.searchTerms at https://tools.oasis-open.org/version-control/browse/wsvn/oslc-core/trunk/specs/oslc-query.html)
* @param limit paging limit
* @param offset paging offset
*
* @return list of OSLC resources, size is less or equal to 'limit'
*
* @throws StoreAccessException if there was a problem with the triplestore (or the
* dataset, more broadly).
* @throws ModelUnmarshallingException if the classes cannot be instantiated or another error
* occurred when working with Jena model.
*/
<T extends IResource> List<T> getResources(URI namedGraphUri, Class<T> clazz,
String prefixes, String where, String searchTerms,
int limit, int offset) throws StoreAccessException, ModelUnmarshallingException;

/**
* Retrieve a Jena model that satisfies the given where parameter as defined in the OSLC Query language (https://tools.oasis-open.org/version-control/svn/oslc-core/trunk/specs/oslc-query.html)
* If the namedGraph is null, the query is applied on all namedGraph in the triplestore.
* The method currently only provides support for terms of type Comparisons, where the operator is 'EQUALS', and the operand is either a String or a URI.
*
* @param namedGraph namedGraphUri URI of a named graph under which resources were stored
* @param prefixes defines the prefixes for prefixed names that appear in the oslc.where query parameter.
* @param where filters the member list, keeping only those member resources that satisfy the boolean test on the member resource properties. (See oslc.where at https://tools.oasis-open.org/version-control/browse/wsvn/oslc-core/trunk/specs/oslc-query.html)
* @param limit paging limit
* @param offset paging offset
*
* @return list of resources, size is less or equal to 'limit'
*
*/
Model getResources(URI namedGraph, String prefixes, String where, int limit, int offset);

/**
* Retrieve a Jena model that satisfies the given where parameter as defined in the OSLC Query language (https://tools.oasis-open.org/version-control/svn/oslc-core/trunk/specs/oslc-query.html)
* If the namedGraph is null, the query is applied on all namedGraph in the triplestore.
* The method currently only provides support for terms of type Comparisons, where the operator is 'EQUALS', and the operand is either a String or a URI.
*
* @param namedGraph namedGraphUri URI of a named graph under which resources were stored
* @param prefixes defines the prefixes for prefixed names that appear in the oslc.where query parameter.
* @param where filters the member list, keeping only those member resources that satisfy the boolean test on the member resource properties
* @param where filters the member list, keeping only those member resources that satisfy the boolean test on the member resource properties. (See oslc.where at https://tools.oasis-open.org/version-control/browse/wsvn/oslc-core/trunk/specs/oslc-query.html)
* @param searchTerms score each member resource using a full text search on it text-valued properties. (See oslc.searchTerms at https://tools.oasis-open.org/version-control/browse/wsvn/oslc-core/trunk/specs/oslc-query.html)
* @param limit paging limit
* @param offset paging offset
*
* @return list of resources, size is less or equal to 'limit'
*
*/
Model getResources(URI namedGraph, String prefixes, String where, int limit, int offset)
throws URISyntaxException;
Model getResources(URI namedGraph, String prefixes, String where, String searchTerms, int limit, int offset);

/**
* Retrieve a single {@link IResource} instance specified by the concrete
Expand Down
Expand Up @@ -162,9 +162,21 @@ public <T extends IResource> List<T> getResources(final URI namedGraph,
return resources.subList(offset, Math.min(resources.size(), offset + limit));
}

@Override
public <T extends IResource> List<T> getResources(URI namedGraphUri, Class<T> clazz, String prefixes, String where,
String searchTerms, int limit, int offset) throws StoreAccessException, ModelUnmarshallingException {
throw new UnsupportedOperationException();
}

@Override
public Model getResources(URI namedGraph, String prefixes, String where, int limit,
int offset) throws URISyntaxException {
int offset) {
throw new UnsupportedOperationException();
}

@Override
public Model getResources(URI namedGraph, String prefixes, String where, String searchTerms, int limit,
int offset) {
throw new UnsupportedOperationException();
}

Expand Down
Expand Up @@ -27,11 +27,13 @@
import org.apache.jena.rdf.model.Statement;
import org.apache.jena.rdf.model.StmtIterator;
import org.apache.jena.rdf.model.impl.ResourceImpl;
import org.apache.jena.sparql.expr.E_Regex;
import org.apache.jena.sparql.modify.request.QuadDataAcc;
import org.apache.jena.sparql.modify.request.UpdateDataInsert;
import org.apache.jena.update.UpdateProcessor;
import org.apache.jena.arq.querybuilder.SelectBuilder;
import org.apache.jena.arq.querybuilder.DescribeBuilder;
import org.apache.jena.arq.querybuilder.ExprFactory;
import org.apache.jena.riot.RiotException;

import java.lang.reflect.Array;
Expand Down Expand Up @@ -254,7 +256,26 @@ public <T extends IResource> List<T> getResources(final URI namedGraph,
}

@Override
public Model getResources(final URI namedGraph, final String prefixes, final String where, final int limit, final int offset) throws URISyntaxException {
public <T extends IResource> List<T> getResources(final URI namedGraph, final Class<T> clazz, final String prefixes,
final String where, final String searchTerms, final int limit, final int offset)
throws StoreAccessException, ModelUnmarshallingException {

String _prefixes = prefixes;
String _where = where;

_prefixes = (StringUtils.isEmpty(_prefixes) ? "" : _prefixes + ",") + oslcQueryPrefixes(clazz);
_where = (StringUtils.isEmpty(_where) ? "" : _where + " and ") + oslcQueryWhere(clazz);
Model model = getResources(namedGraph, _prefixes, _where, searchTerms, limit, offset);
return getResourcesFromModel(model, clazz);
}

@Override
public Model getResources(final URI namedGraph, final String prefixes, final String where, final int limit, final int offset) {
return getResources(namedGraph, prefixes, where, null, limit, offset);
}

@Override
public Model getResources(final URI namedGraph, final String prefixes, final String where, final String searchTerms, final int limit, final int offset) {

if (namedGraph != null) {
//Make sure the designated namedGraph exists, if it is specified.
Expand All @@ -264,7 +285,7 @@ public Model getResources(final URI namedGraph, final String prefixes, final Str
}
}

SelectBuilder sparqlWhereQuery = constructSparqlWhere (prefixes, where, limit, offset);
SelectBuilder sparqlWhereQuery = constructSparqlWhere (prefixes, where, searchTerms, limit, offset);
DescribeBuilder describeBuilder = new DescribeBuilder();
if (namedGraph != null) {
describeBuilder.addVar("s")
Expand Down Expand Up @@ -350,6 +371,14 @@ public void removeAll() {
queryExecutor.prepareSparqlUpdate("CLEAR ALL").execute();
}

private <T extends IResource> String oslcQueryPrefixes(final Class<T> clazz) {
return "rdf=" + "<" + org.apache.jena.vocabulary.RDF.uri + ">";
}

private <T extends IResource> String oslcQueryWhere(final Class<T> clazz) {
return "rdf:type=" + "<" + getResourceNsUri(clazz) + ">";
}

private <T extends IResource> List<T> getResourcesFromModel(final Model model,
final Class<T> clazz) throws ModelUnmarshallingException, StoreAccessException {
try {
Expand Down Expand Up @@ -461,7 +490,7 @@ private Model modelFromQueryFlatPaged(final URI namedGraph, final URI type, fina
}

//This method currently only provides support for terms of type Comparisons, where the operator is 'EQUALS', and the operand is either a String or a URI.
private SelectBuilder constructSparqlWhere(final String prefixes, final String where, final int limit, final int offset) {
private SelectBuilder constructSparqlWhere(final String prefixes, final String where, final String searchTerms, final int limit, final int offset) {

SelectBuilder distinctResourcesQuery = new SelectBuilder();

Expand All @@ -470,65 +499,72 @@ private SelectBuilder constructSparqlWhere(final String prefixes, final String w
try {
if (!StringUtils.isEmpty(prefixes)) {
prefixesMap = QueryUtils.parsePrefixes(prefixes);
for (Entry<String, String> prefix : prefixesMap.entrySet()) {
distinctResourcesQuery.addPrefix(prefix.getKey(), prefix.getValue());
}
}
} catch (ParseException e) {
throw new IllegalArgumentException("prefixesExpression could not be parsed", e);
}
for (Entry<String, String> prefix : prefixesMap.entrySet()) {
distinctResourcesQuery.addPrefix(prefix.getKey(), prefix.getValue());
}

//Setup where
distinctResourcesQuery
.addVar( "s" )
.setDistinct(true)
.addWhere( "?s", "?p", "?o");

//Setup where
WhereClause whereClause = null;
try {
if (!StringUtils.isEmpty(where)) {
whereClause = QueryUtils.parseWhere(where, prefixesMap);
List<SimpleTerm> parseChildren = whereClause.children();
for (Iterator<SimpleTerm> iterator = parseChildren.iterator(); iterator.hasNext();) {
SimpleTerm simpleTerm = iterator.next();
Type termType = simpleTerm.type();
PName property = simpleTerm.property();

if (!termType.equals(Type.COMPARISON)){
throw new UnsupportedOperationException("only support for terms of type Comparisons");
}
ComparisonTerm aComparisonTerm = (ComparisonTerm) simpleTerm;
if (!aComparisonTerm.operator().equals(Operator.EQUALS)){
throw new UnsupportedOperationException("only support for terms of type Comparisons, where the operator is 'EQUALS'");
}

Value comparisonOperand = aComparisonTerm.operand();
Value.Type operandType = comparisonOperand.type();
String predicate;
if (property.local.equals("*")) {
predicate = "?p";
}
else {
predicate = property.toString();
}

switch (operandType) {
case STRING:
StringValue stringOperand = (StringValue) comparisonOperand;
distinctResourcesQuery.addWhere( "?s", predicate, stringOperand.value());
break;
case URI_REF:
UriRefValue uriOperand = (UriRefValue) comparisonOperand;
distinctResourcesQuery.addWhere( "?s", predicate, new ResourceImpl(uriOperand.value()));
break;
default:
throw new UnsupportedOperationException("only support for terms of type Comparisons, where the operator is 'EQUALS', and the operand is either a String or a URI");
}
}
}
} catch (ParseException e) {
throw new IllegalArgumentException("whereExpression could not be parsed", e);
}

distinctResourcesQuery
.addVar( "s" )
.setDistinct(true)
.addWhere( "?s", "?p", "?o");

List<SimpleTerm> parseChildren = whereClause.children();
for (Iterator<SimpleTerm> iterator = parseChildren.iterator(); iterator.hasNext();) {
SimpleTerm simpleTerm = iterator.next();
Type termType = simpleTerm.type();
PName property = simpleTerm.property();

if (!termType.equals(Type.COMPARISON)){
throw new UnsupportedOperationException("only support for terms of type Comparisons");
}
ComparisonTerm aComparisonTerm = (ComparisonTerm) simpleTerm;
if (!aComparisonTerm.operator().equals(Operator.EQUALS)){
throw new UnsupportedOperationException("only support for terms of type Comparisons, where the operator is 'EQUALS'");
}

Value comparisonOperand = aComparisonTerm.operand();
Value.Type operandType = comparisonOperand.type();
String predicate;
if (property.local.equals("*")) {
predicate = "?p";
}
else {
predicate = property.toString();
}

switch (operandType) {
case STRING:
StringValue stringOperand = (StringValue) comparisonOperand;
distinctResourcesQuery.addWhere( "?s", predicate, stringOperand.value());
break;
case URI_REF:
UriRefValue uriOperand = (UriRefValue) comparisonOperand;
distinctResourcesQuery.addWhere( "?s", predicate, new ResourceImpl(uriOperand.value()));
break;
default:
throw new UnsupportedOperationException("only support for terms of type Comparisons, where the operator is 'EQUALS', and the operand is either a String or a URI");
}

//Setup searchTerms
//Add a sparql filter "FILTER regex(?o, "<searchTerms>", "i")" to the distinctResourcesQuery
if (!StringUtils.isEmpty(searchTerms)) {
ExprFactory factory = new ExprFactory();
E_Regex regex = factory.regex(factory.str("?o"), searchTerms, "i");
distinctResourcesQuery.addFilter(regex);
}

if (limit > 0) {
Expand Down
Expand Up @@ -17,6 +17,7 @@
import org.apache.jena.query.Dataset;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
Expand Down Expand Up @@ -65,4 +66,47 @@ public void testStoreHandlesNonExistentPath() throws IOException {
final Path tempDirectory = Paths.get("/tmp/try_tdb"); // make sure `ls -l /tmp` shows correct permissions
StoreFactory.onDisk(tempDirectory);
}

@Override
@Ignore("Not implemented yet")
public void testStoreQueryForAllRequirementResources()
throws StoreAccessException, ModelUnmarshallingException, URISyntaxException {
}

@Override
@Ignore("Not implemented yet")
public void testStoreQueryForRequirementResourcesWithFreeTextSearch()
throws StoreAccessException, ModelUnmarshallingException, URISyntaxException {
}

@Override
@Ignore("Not implemented yet")
public void testStoreQueryForRequirementResourcesWithWhereFilter()
throws StoreAccessException, ModelUnmarshallingException, URISyntaxException {
}

@Override
@Ignore("Not implemented yet")
public void testStoreQueryForRequirementResourcesWithFreeTextSearchAndWhereFilter()
throws StoreAccessException, ModelUnmarshallingException, URISyntaxException {
}

@Override
@Ignore("Not implemented yet")
public void testStoreQueryForRequirementResourcesWithNoMatch()
throws StoreAccessException, ModelUnmarshallingException, URISyntaxException {
}

@Override
@Ignore("Not implemented yet")
public void testStoreQueryForAllResources()
throws StoreAccessException, ModelUnmarshallingException, URISyntaxException {
}

@Override
@Ignore("Not implemented yet")
public void testStoreQueryForAllResourcesWithFreeTextSearch()
throws StoreAccessException, ModelUnmarshallingException, URISyntaxException {
}

}
Expand Up @@ -15,11 +15,13 @@
*/

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import org.eclipse.lyo.store.internals.DatasetBuilder;
import org.eclipse.lyo.store.internals.JenaTdbStoreImpl;
import org.junit.Before;
import org.junit.Ignore;

/**
* DatasetBuilderTest is .
Expand All @@ -46,4 +48,46 @@ protected JenaTdbStoreImpl buildStore() {
}
}

@Override
@Ignore("Not implemented yet")
public void testStoreQueryForAllRequirementResources()
throws StoreAccessException, ModelUnmarshallingException, URISyntaxException {
}

@Override
@Ignore("Not implemented yet")
public void testStoreQueryForRequirementResourcesWithFreeTextSearch()
throws StoreAccessException, ModelUnmarshallingException, URISyntaxException {
}

@Override
@Ignore("Not implemented yet")
public void testStoreQueryForRequirementResourcesWithWhereFilter()
throws StoreAccessException, ModelUnmarshallingException, URISyntaxException {
}

@Override
@Ignore("Not implemented yet")
public void testStoreQueryForRequirementResourcesWithFreeTextSearchAndWhereFilter()
throws StoreAccessException, ModelUnmarshallingException, URISyntaxException {
}

@Override
@Ignore("Not implemented yet")
public void testStoreQueryForRequirementResourcesWithNoMatch()
throws StoreAccessException, ModelUnmarshallingException, URISyntaxException {
}

@Override
@Ignore("Not implemented yet")
public void testStoreQueryForAllResources()
throws StoreAccessException, ModelUnmarshallingException, URISyntaxException {
}

@Override
@Ignore("Not implemented yet")
public void testStoreQueryForAllResourcesWithFreeTextSearch()
throws StoreAccessException, ModelUnmarshallingException, URISyntaxException {
}

}

0 comments on commit 5154831

Please sign in to comment.