http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/917e7a57/extras/indexing/src/main/java/mvm/rya/indexing/GeoIndexer.java ---------------------------------------------------------------------- diff --git a/extras/indexing/src/main/java/mvm/rya/indexing/GeoIndexer.java b/extras/indexing/src/main/java/mvm/rya/indexing/GeoIndexer.java index 7c04903..40dfeec 100644 --- a/extras/indexing/src/main/java/mvm/rya/indexing/GeoIndexer.java +++ b/extras/indexing/src/main/java/mvm/rya/indexing/GeoIndexer.java @@ -1,5 +1,10 @@ package mvm.rya.indexing; +import org.openrdf.model.Statement; +import org.openrdf.query.QueryEvaluationException; + +import com.vividsolutions.jts.geom.Geometry; + /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -8,9 +13,9 @@ package mvm.rya.indexing; * 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 @@ -22,25 +27,15 @@ package mvm.rya.indexing; import info.aduna.iteration.CloseableIteration; - -import java.io.IOException; -import java.util.Set; - import mvm.rya.api.persist.index.RyaSecondaryIndexer; -import org.openrdf.model.Statement; -import org.openrdf.model.URI; -import org.openrdf.query.QueryEvaluationException; - -import com.vividsolutions.jts.geom.Geometry; - /** * A repository to store, index, and retrieve {@link Statement}s based on geospatial features. */ public interface GeoIndexer extends RyaSecondaryIndexer { /** - * Returns statements that contain a geometry that is equal to the queried {@link Geometry} and meet the {@link StatementContraints}. - * + * Returns statements that contain a geometry that is equal to the queried {@link Geometry} and meet the {@link StatementConstraints}. + * * <p> * From Wikipedia (http://en.wikipedia.org/wiki/DE-9IM): * <ul> @@ -48,110 +43,110 @@ public interface GeoIndexer extends RyaSecondaryIndexer { * "Two geometries are topologically equal if their interiors intersect and no part of the interior or boundary of one geometry intersects the exterior of the other" * <li>"A is equal to B if A is within B and A contains B" * </ul> - * + * * @param query * the queried geometry * @param contraints - * the {@link StatementContraints} + * the {@link StatementConstraints} * @return */ - public abstract CloseableIteration<Statement, QueryEvaluationException> queryEquals(Geometry query, StatementContraints contraints); + public abstract CloseableIteration<Statement, QueryEvaluationException> queryEquals(Geometry query, StatementConstraints contraints); /** - * Returns statements that contain a geometry that is disjoint to the queried {@link Geometry} and meet the {@link StatementContraints}. - * + * Returns statements that contain a geometry that is disjoint to the queried {@link Geometry} and meet the {@link StatementConstraints}. + * * <p> * From Wikipedia (http://en.wikipedia.org/wiki/DE-9IM): * <ul> * <li>"A and B are disjoint if they have no point in common. They form a set of disconnected geometries." * <li>"A and B are disjoint if A does not intersect B" * </ul> - * + * * @param query * the queried geometry * @param contraints - * the {@link StatementContraints} + * the {@link StatementConstraints} * @return */ - public abstract CloseableIteration<Statement, QueryEvaluationException> queryDisjoint(Geometry query, StatementContraints contraints); + public abstract CloseableIteration<Statement, QueryEvaluationException> queryDisjoint(Geometry query, StatementConstraints contraints); /** - * Returns statements that contain a geometry that Intersects the queried {@link Geometry} and meet the {@link StatementContraints}. - * + * Returns statements that contain a geometry that Intersects the queried {@link Geometry} and meet the {@link StatementConstraints}. + * * <p> * From Wikipedia (http://en.wikipedia.org/wiki/DE-9IM): * <ul> * <li>"a intersects b: geometries a and b have at least one point in common." * <li>"not Disjoint" * </ul> - * - * + * + * * @param query * the queried geometry * @param contraints - * the {@link StatementContraints} + * the {@link StatementConstraints} * @return */ - public abstract CloseableIteration<Statement, QueryEvaluationException> queryIntersects(Geometry query, StatementContraints contraints); + public abstract CloseableIteration<Statement, QueryEvaluationException> queryIntersects(Geometry query, StatementConstraints contraints); /** - * Returns statements that contain a geometry that Touches the queried {@link Geometry} and meet the {@link StatementContraints}. - * + * Returns statements that contain a geometry that Touches the queried {@link Geometry} and meet the {@link StatementConstraints}. + * * <p> * From Wikipedia (http://en.wikipedia.org/wiki/DE-9IM): * <ul> * <li>"a touches b, they have at least one boundary point in common, but no interior points." * </ul> - * - * + * + * * @param query * the queried geometry * @param contraints - * the {@link StatementContraints} + * the {@link StatementConstraints} * @return */ - public abstract CloseableIteration<Statement, QueryEvaluationException> queryTouches(Geometry query, StatementContraints contraints); + public abstract CloseableIteration<Statement, QueryEvaluationException> queryTouches(Geometry query, StatementConstraints contraints); /** - * Returns statements that contain a geometry that crosses the queried {@link Geometry} and meet the {@link StatementContraints}. - * + * Returns statements that contain a geometry that crosses the queried {@link Geometry} and meet the {@link StatementConstraints}. + * * <p> * From Wikipedia (http://en.wikipedia.org/wiki/DE-9IM): * <ul> * <li> * "a crosses b, they have some but not all interior points in common (and the dimension of the intersection is less than that of at least one of them)." * </ul> - * + * * @param query * the queried geometry * @param contraints - * the {@link StatementContraints} + * the {@link StatementConstraints} * @return */ - public abstract CloseableIteration<Statement, QueryEvaluationException> queryCrosses(Geometry query, StatementContraints contraints); + public abstract CloseableIteration<Statement, QueryEvaluationException> queryCrosses(Geometry query, StatementConstraints contraints); /** - * Returns statements that contain a geometry that is Within the queried {@link Geometry} and meet the {@link StatementContraints}. - * + * Returns statements that contain a geometry that is Within the queried {@link Geometry} and meet the {@link StatementConstraints}. + * * <p> * From Wikipedia (http://en.wikipedia.org/wiki/DE-9IM): * <ul> * <li>"a is within b, a lies in the interior of b" * <li>Same as: "Contains(b,a)" * </ul> - * - * + * + * * @param query * the queried geometry * @param contraints - * the {@link StatementContraints} + * the {@link StatementConstraints} * @return */ - public abstract CloseableIteration<Statement, QueryEvaluationException> queryWithin(Geometry query, StatementContraints contraints); + public abstract CloseableIteration<Statement, QueryEvaluationException> queryWithin(Geometry query, StatementConstraints contraints); /** - * Returns statements that contain a geometry that Contains the queried {@link Geometry} and meet the {@link StatementContraints}. - * + * Returns statements that contain a geometry that Contains the queried {@link Geometry} and meet the {@link StatementConstraints}. + * * <p> * From Wikipedia (http://en.wikipedia.org/wiki/DE-9IM): * <ul> @@ -159,43 +154,32 @@ public interface GeoIndexer extends RyaSecondaryIndexer { * "a 'contains' b iff no points of b lie in the exterior of a, and at least one point of the interior of b lies in the interior of a" * <li>Same: Within(b,a) * </ul> - * - * + * + * * @param query * the queried geometry * @param contraints - * the {@link StatementContraints} + * the {@link StatementConstraints} * @return */ - public abstract CloseableIteration<Statement, QueryEvaluationException> queryContains(Geometry query, StatementContraints contraints); + public abstract CloseableIteration<Statement, QueryEvaluationException> queryContains(Geometry query, StatementConstraints contraints); /** - * Returns statements that contain a geometry that Overlaps the queried {@link Geometry} and meet the {@link StatementContraints}. - * + * Returns statements that contain a geometry that Overlaps the queried {@link Geometry} and meet the {@link StatementConstraints}. + * * <p> * From Wikipedia (http://en.wikipedia.org/wiki/DE-9IM): * <ul> * <li>a crosses b, they have some but not all interior points in common (and the dimension of the intersection is less than that of at * least one of them). * </ul> - * - * + * + * * @param query * the queried geometry * @param contraints - * the {@link StatementContraints} + * the {@link StatementConstraints} * @return */ - public abstract CloseableIteration<Statement, QueryEvaluationException> queryOverlaps(Geometry query, StatementContraints contraints); - - /** - * @return the set of predicates indexed by the indexer. - */ - public abstract Set<URI> getIndexablePredicates(); - - @Override - public abstract void flush() throws IOException; - - @Override - public abstract void close() throws IOException; + public abstract CloseableIteration<Statement, QueryEvaluationException> queryOverlaps(Geometry query, StatementConstraints contraints); }
http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/917e7a57/extras/indexing/src/main/java/mvm/rya/indexing/IteratorFactory.java ---------------------------------------------------------------------- diff --git a/extras/indexing/src/main/java/mvm/rya/indexing/IteratorFactory.java b/extras/indexing/src/main/java/mvm/rya/indexing/IteratorFactory.java index d61c5ae..eb88d99 100644 --- a/extras/indexing/src/main/java/mvm/rya/indexing/IteratorFactory.java +++ b/extras/indexing/src/main/java/mvm/rya/indexing/IteratorFactory.java @@ -59,7 +59,7 @@ public class IteratorFactory { private void performQuery() throws QueryEvaluationException { - StatementContraints contraints = new StatementContraints(); + StatementConstraints contraints = new StatementConstraints(); // get the context (i.e. named graph) of the statement and use that in the query QueryModelNode parentNode = match.getSubjectVar().getParentNode(); http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/917e7a57/extras/indexing/src/main/java/mvm/rya/indexing/KeyParts.java ---------------------------------------------------------------------- diff --git a/extras/indexing/src/main/java/mvm/rya/indexing/KeyParts.java b/extras/indexing/src/main/java/mvm/rya/indexing/KeyParts.java index 2caf81c..2dd7a73 100644 --- a/extras/indexing/src/main/java/mvm/rya/indexing/KeyParts.java +++ b/extras/indexing/src/main/java/mvm/rya/indexing/KeyParts.java @@ -8,9 +8,9 @@ package mvm.rya.indexing; * 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 @@ -24,9 +24,6 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; -import mvm.rya.indexing.accumulo.Md5Hash; -import mvm.rya.indexing.accumulo.StatementSerializer; - import org.apache.accumulo.core.data.Value; import org.apache.commons.codec.binary.StringUtils; import org.apache.hadoop.io.Text; @@ -44,25 +41,25 @@ import org.openrdf.model.impl.URIImpl; * rowkey = datetime 0x/00 uniquesuffix * contraintPrefix = 0x/00 hash([subject][predicate]) * uniquesuffix = some bytes to make it unique, like hash(statement). - * + * * The instance is in one of two modes depending on the constructor: - * storage mode -- construct with a triple statement, get an iterator of keys to store. + * storage mode -- construct with a triple statement, get an iterator of keys to store. * query mode -- construct with a statement and query constraints, get the key prefix to search. - * + * * this has the flavor of an immutable object * This is independent of the underlying database engine - * + * * @author David.Lotts * */ -public class KeyParts implements Iterable<KeyParts> { +public class KeyParts implements Iterable<KeyParts> { private static final String CQ_S_P_AT = "spo"; private static final String CQ_P_AT = "po"; private static final String CQ_S_AT = "so"; private static final String CQ_O_AT = "o"; public static final String CQ_BEGIN = "begin"; public static final String CQ_END = "end"; - + public static final byte[] HASH_PREFIX = new byte[] {0}; public static final byte[] HASH_PREFIX_FOLLOWING = new byte[] {1}; @@ -73,16 +70,16 @@ public class KeyParts implements Iterable<KeyParts> { final private TemporalInstant instant; final private Statement statement; final private boolean queryMode; - KeyParts(Text constraintPrefix, TemporalInstant instant, String cf, String cq) { - this.queryMode = true; // query mode - this.storeKey = null; - this.statement = null; + KeyParts(final Text constraintPrefix, final TemporalInstant instant, final String cf, final String cq) { + queryMode = true; // query mode + storeKey = null; + statement = null; this.constraintPrefix = constraintPrefix; this.instant = instant; this.cf = new Text(cf); this.cq = new Text(cq); } - + /** * this is the value to index. * @return @@ -92,34 +89,35 @@ public class KeyParts implements Iterable<KeyParts> { return new Value(StringUtils.getBytesUtf8(StatementSerializer.writeStatement(statement))); } - public KeyParts(Statement statement, TemporalInstant instant2) { - this.queryMode = false; // store mode - this.storeKey = null; - this.constraintPrefix = null; + public KeyParts(final Statement statement, final TemporalInstant instant2) { + queryMode = false; // store mode + storeKey = null; + constraintPrefix = null; this.statement = statement; - this.instant = instant2; - this.cf = null; - this.cq = null; + instant = instant2; + cf = null; + cq = null; } - private KeyParts(Text keyText, Text cf, Text cq, Statement statement) { - this.queryMode = false; // store mode - this.constraintPrefix = null; + private KeyParts(final Text keyText, final Text cf, final Text cq, final Statement statement) { + queryMode = false; // store mode + constraintPrefix = null; this.statement = statement; - this.instant = null; - this.storeKey = keyText; + instant = null; + storeKey = keyText; this.cf = cf; this.cq = cq; } - + @Override public Iterator<KeyParts> iterator() { - final String[] strategies = new String[] { + final String[] strategies = new String[] { CQ_O_AT, CQ_S_P_AT, CQ_P_AT, CQ_S_AT } ; // CQ_END? - assert !queryMode : "iterator for queryMode is not immplemented" ; - if (queryMode) - return null; + assert !queryMode : "iterator for queryMode is not immplemented" ; + if (queryMode) { + return null; + } // if (!queryMode) return new Iterator<KeyParts>() { @@ -170,10 +168,10 @@ public class KeyParts implements Iterable<KeyParts> { } }; } - + public byte[] getStoreKey() { assert !queryMode : "must be in store Mode, store keys are not initialized."; - return this.storeKey.copyBytes(); + return storeKey.copyBytes(); } /** @@ -181,19 +179,20 @@ public class KeyParts implements Iterable<KeyParts> { * @return the row key for range queries. */ public Text getQueryKey() { - return getQueryKey(this.instant); + return getQueryKey(instant); }; /** * Query key is the prefix plus the datetime, but no uniqueness at the end. - * + * * @return the row key for range queries. */ - public Text getQueryKey(TemporalInstant theInstant) { + public Text getQueryKey(final TemporalInstant theInstant) { assert queryMode : "must be in query Mode, query keys are not initialized."; - Text keyText = new Text(); - if (constraintPrefix != null) - appendBytes(constraintPrefix.copyBytes(), keyText); + final Text keyText = new Text(); + if (constraintPrefix != null) { + appendBytes(constraintPrefix.copyBytes(), keyText); + } appendInstant(theInstant, keyText); return keyText; }; @@ -202,29 +201,29 @@ public class KeyParts implements Iterable<KeyParts> { public String toString() { return "KeyParts [contraintPrefix=" + toHumanString(constraintPrefix) + ", instant=" + toHumanString(instant.getAsKeyBytes()) + ", cf=" + cf + ", cq=" + cq + "]"; } - private static void appendSubject(Statement statement, Text keyText) { - Value statementValue = new Value(StatementSerializer.writeSubject(statement).getBytes()); - byte[] hashOfValue = uniqueFromValueForKey(statementValue); - appendBytes(HASH_PREFIX, keyText); // prefix the hash with a zero byte. + private static void appendSubject(final Statement statement, final Text keyText) { + final Value statementValue = new Value(StatementSerializer.writeSubject(statement).getBytes()); + final byte[] hashOfValue = uniqueFromValueForKey(statementValue); + appendBytes(HASH_PREFIX, keyText); // prefix the hash with a zero byte. appendBytes(hashOfValue, keyText); } - private static void appendPredicate(Statement statement, Text keyText) { - Value statementValue = new Value(StringUtils.getBytesUtf8(StatementSerializer.writePredicate(statement))); - byte[] hashOfValue = uniqueFromValueForKey(statementValue); - appendBytes(HASH_PREFIX, keyText); // prefix the hash with a zero byte. + private static void appendPredicate(final Statement statement, final Text keyText) { + final Value statementValue = new Value(StringUtils.getBytesUtf8(StatementSerializer.writePredicate(statement))); + final byte[] hashOfValue = uniqueFromValueForKey(statementValue); + appendBytes(HASH_PREFIX, keyText); // prefix the hash with a zero byte. appendBytes(hashOfValue, keyText); } - private static void appendInstant(TemporalInstant instant, Text keyText) { - byte[] bytes = instant.getAsKeyBytes(); + private static void appendInstant(final TemporalInstant instant, final Text keyText) { + final byte[] bytes = instant.getAsKeyBytes(); appendBytes(bytes, keyText); } - private static void appendSubjectPredicate(Statement statement, Text keyText) { - Value statementValue = new Value(StringUtils.getBytesUtf8(StatementSerializer.writeSubjectPredicate(statement))); - byte[] hashOfValue = uniqueFromValueForKey(statementValue); - appendBytes(HASH_PREFIX, keyText); // prefix the hash with a zero byte. + private static void appendSubjectPredicate(final Statement statement, final Text keyText) { + final Value statementValue = new Value(StringUtils.getBytesUtf8(StatementSerializer.writeSubjectPredicate(statement))); + final byte[] hashOfValue = uniqueFromValueForKey(statementValue); + appendBytes(HASH_PREFIX, keyText); // prefix the hash with a zero byte. appendBytes(hashOfValue, keyText); } @@ -233,12 +232,12 @@ public class KeyParts implements Iterable<KeyParts> { * @param bytes append this * @param keyText text to append to */ - private static void appendBytes(byte[] bytes, Text keyText) { + private static void appendBytes(final byte[] bytes, final Text keyText) { keyText.append(bytes, 0, bytes.length); } /** - * Get a collision unlikely hash string and append to the key, + * Get a collision unlikely hash string and append to the key, * so that if two keys have the same value, then they will be the same, * if two different values that occur at the same time there keys are different. * If the application uses a very large number of statements at the exact same time, @@ -246,20 +245,20 @@ public class KeyParts implements Iterable<KeyParts> { * @param statement * @param keyText */ - public static void appendUniqueness(Statement statement, Text keyText) { + public static void appendUniqueness(final Statement statement, final Text keyText) { keyText.append(HASH_PREFIX, 0, 1); // delimiter - Value statementValue = new Value(StringUtils.getBytesUtf8(StatementSerializer.writeStatement(statement))); - byte[] hashOfValue = Md5Hash.md5Binary(statementValue); + final Value statementValue = new Value(StringUtils.getBytesUtf8(StatementSerializer.writeStatement(statement))); + final byte[] hashOfValue = Md5Hash.md5Binary(statementValue); keyText.append(hashOfValue, 0, hashOfValue.length); } /** - * Get a collision unlikely hash string to append to the key, + * Get a collision unlikely hash string to append to the key, * so that if two keys have the same value, then they will be the same, * if two different values that occur at the same time there keys are different. * @param value * @return */ - private static byte[] uniqueFromValueForKey(Value value) { + private static byte[] uniqueFromValueForKey(final Value value) { return Md5Hash.md5Binary(value); } @@ -270,25 +269,26 @@ public class KeyParts implements Iterable<KeyParts> { * @param contraints * @return */ - static public List<KeyParts> keyPartsForQuery(TemporalInstant queryInstant, StatementContraints contraints) { - List<KeyParts> keys = new LinkedList<KeyParts>(); - URI urlNull = new URIImpl("urn:null"); - Resource currentContext = contraints.getContext(); - boolean hasSubj = contraints.hasSubject(); + static public List<KeyParts> keyPartsForQuery(final TemporalInstant queryInstant, final StatementConstraints contraints) { + final List<KeyParts> keys = new LinkedList<KeyParts>(); + final URI urlNull = new URIImpl("urn:null"); + final Resource currentContext = contraints.getContext(); + final boolean hasSubj = contraints.hasSubject(); if (contraints.hasPredicates()) { - for (URI nextPredicate : contraints.getPredicates()) { - Text contraintPrefix = new Text(); - Statement statement = new ContextStatementImpl(hasSubj ? contraints.getSubject() : urlNull, nextPredicate, urlNull, contraints.getContext()); - if (hasSubj) - appendSubjectPredicate(statement, contraintPrefix); - else - appendPredicate(statement, contraintPrefix); + for (final URI nextPredicate : contraints.getPredicates()) { + final Text contraintPrefix = new Text(); + final Statement statement = new ContextStatementImpl(hasSubj ? contraints.getSubject() : urlNull, nextPredicate, urlNull, contraints.getContext()); + if (hasSubj) { + appendSubjectPredicate(statement, contraintPrefix); + } else { + appendPredicate(statement, contraintPrefix); + } keys.add(new KeyParts(contraintPrefix, queryInstant, (currentContext==null)?"":currentContext.toString(), hasSubj?CQ_S_P_AT:CQ_P_AT )); } } else if (contraints.hasSubject()) { // and no predicates - Text contraintPrefix = new Text(); - Statement statement = new StatementImpl(contraints.getSubject(), urlNull, urlNull); + final Text contraintPrefix = new Text(); + final Statement statement = new StatementImpl(contraints.getSubject(), urlNull, urlNull); appendSubject(statement, contraintPrefix); keys.add( new KeyParts(contraintPrefix, queryInstant, (currentContext==null)?"":currentContext.toString(), CQ_S_AT) ); } @@ -303,17 +303,18 @@ public class KeyParts implements Iterable<KeyParts> { * @param value * @return Human readable representation. */ - public static String toHumanString(Value value) { + public static String toHumanString(final Value value) { return toHumanString(value==null?null:value.get()); } - public static String toHumanString(Text text) { + public static String toHumanString(final Text text) { return toHumanString(text==null?null:text.copyBytes()); } - public static String toHumanString(byte[] bytes) { - if (bytes==null) - return "{null}"; - StringBuilder sb = new StringBuilder(); - for (byte b : bytes) { + public static String toHumanString(final byte[] bytes) { + if (bytes==null) { + return "{null}"; + } + final StringBuilder sb = new StringBuilder(); + for (final byte b : bytes) { if ((b > 0x7e) || (b < 32)) { sb.append("{"); sb.append(Integer.toHexString( b & 0xff )); // Lop off the sign extended ones. @@ -322,10 +323,11 @@ public class KeyParts implements Iterable<KeyParts> { sb.append("{"); sb.append((char)b); sb.append("}"); - } else - sb.append((char)b); + } else { + sb.append((char)b); + } } return sb.toString(); } - + } http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/917e7a57/extras/indexing/src/main/java/mvm/rya/indexing/Md5Hash.java ---------------------------------------------------------------------- diff --git a/extras/indexing/src/main/java/mvm/rya/indexing/Md5Hash.java b/extras/indexing/src/main/java/mvm/rya/indexing/Md5Hash.java new file mode 100644 index 0000000..0e83822 --- /dev/null +++ b/extras/indexing/src/main/java/mvm/rya/indexing/Md5Hash.java @@ -0,0 +1,44 @@ +package mvm.rya.indexing; + +import org.apache.accumulo.core.data.Value; + +/* + * 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. + */ + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.binary.StringUtils; +import org.apache.commons.codec.digest.DigestUtils; + +/** + * Utility methods for generating hashes. Note that MD5 is 16 bytes, or 32 Hex chars. To make it smaller (but still printable), this class + * Base64 encodes those 16 bytes into 22 chars. + */ +public class Md5Hash { + public static String md5Base64(final byte[] data) { + return Base64.encodeBase64URLSafeString(DigestUtils.md5(data)); + } + + public static String md5Base64(final String string) { + return md5Base64(StringUtils.getBytesUtf8(string)); + } + + public static byte[] md5Binary(final Value value) { + return DigestUtils.md5(value.get()); + } +} http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/917e7a57/extras/indexing/src/main/java/mvm/rya/indexing/SearchFunction.java ---------------------------------------------------------------------- diff --git a/extras/indexing/src/main/java/mvm/rya/indexing/SearchFunction.java b/extras/indexing/src/main/java/mvm/rya/indexing/SearchFunction.java index ce94556..6a19ee0 100644 --- a/extras/indexing/src/main/java/mvm/rya/indexing/SearchFunction.java +++ b/extras/indexing/src/main/java/mvm/rya/indexing/SearchFunction.java @@ -30,7 +30,7 @@ import org.openrdf.query.QueryEvaluationException; public interface SearchFunction { /** - * Search the indices for the given terms and return {@link Statement}s that meet the {@link StatementContraints} + * Search the indices for the given terms and return {@link Statement}s that meet the {@link StatementConstraints} * * @param searchTerms * the search terms @@ -39,7 +39,7 @@ public interface SearchFunction { * @return * @throws QueryEvaluationException */ - public abstract CloseableIteration<Statement, QueryEvaluationException> performSearch(String searchTerms, StatementContraints contraints) + public abstract CloseableIteration<Statement, QueryEvaluationException> performSearch(String searchTerms, StatementConstraints contraints) throws QueryEvaluationException; } http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/917e7a57/extras/indexing/src/main/java/mvm/rya/indexing/StatementConstraints.java ---------------------------------------------------------------------- diff --git a/extras/indexing/src/main/java/mvm/rya/indexing/StatementConstraints.java b/extras/indexing/src/main/java/mvm/rya/indexing/StatementConstraints.java new file mode 100644 index 0000000..e8f1d4e --- /dev/null +++ b/extras/indexing/src/main/java/mvm/rya/indexing/StatementConstraints.java @@ -0,0 +1,73 @@ +package mvm.rya.indexing; + +/* + * 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. + */ + + + +import java.util.Set; + +import org.openrdf.model.Resource; +import org.openrdf.model.URI; + +public class StatementConstraints { + private Resource context = null; + private Resource subject = null; + private Set<URI> predicates = null; + + public StatementConstraints setContext(Resource context) { + this.context = context; + return this; + } + + public StatementConstraints setPredicates(Set<URI> predicates) { + this.predicates = predicates; + return this; + } + + public StatementConstraints setSubject(Resource subject) { + this.subject = subject; + return this; + } + + public Resource getContext() { + return context; + } + + public Set<URI> getPredicates() { + return predicates; + } + + public Resource getSubject() { + return subject; + } + + public boolean hasSubject() { + return subject != null; + } + + public boolean hasPredicates() { + return predicates != null && !predicates.isEmpty(); + } + + public boolean hasContext() { + return context != null; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/917e7a57/extras/indexing/src/main/java/mvm/rya/indexing/StatementContraints.java ---------------------------------------------------------------------- diff --git a/extras/indexing/src/main/java/mvm/rya/indexing/StatementContraints.java b/extras/indexing/src/main/java/mvm/rya/indexing/StatementContraints.java deleted file mode 100644 index 437c74d..0000000 --- a/extras/indexing/src/main/java/mvm/rya/indexing/StatementContraints.java +++ /dev/null @@ -1,73 +0,0 @@ -package mvm.rya.indexing; - -/* - * 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. - */ - - - -import java.util.Set; - -import org.openrdf.model.Resource; -import org.openrdf.model.URI; - -public class StatementContraints { - private Resource context = null; - private Resource subject = null; - private Set<URI> predicates = null; - - public StatementContraints setContext(Resource context) { - this.context = context; - return this; - } - - public StatementContraints setPredicates(Set<URI> predicates) { - this.predicates = predicates; - return this; - } - - public StatementContraints setSubject(Resource subject) { - this.subject = subject; - return this; - } - - public Resource getContext() { - return context; - } - - public Set<URI> getPredicates() { - return predicates; - } - - public Resource getSubject() { - return subject; - } - - public boolean hasSubject() { - return subject != null; - } - - public boolean hasPredicates() { - return predicates != null && !predicates.isEmpty(); - } - - public boolean hasContext() { - return context != null; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/917e7a57/extras/indexing/src/main/java/mvm/rya/indexing/StatementSerializer.java ---------------------------------------------------------------------- diff --git a/extras/indexing/src/main/java/mvm/rya/indexing/StatementSerializer.java b/extras/indexing/src/main/java/mvm/rya/indexing/StatementSerializer.java new file mode 100644 index 0000000..107f69d --- /dev/null +++ b/extras/indexing/src/main/java/mvm/rya/indexing/StatementSerializer.java @@ -0,0 +1,225 @@ +package mvm.rya.indexing; + +/* + * 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. + */ + + + +import java.io.IOException; +import java.util.Set; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.Validate; +import org.openrdf.model.Literal; +import org.openrdf.model.Resource; +import org.openrdf.model.Statement; +import org.openrdf.model.URI; +import org.openrdf.model.Value; +import org.openrdf.model.ValueFactory; +import org.openrdf.model.impl.ContextStatementImpl; +import org.openrdf.model.impl.StatementImpl; +import org.openrdf.model.impl.ValueFactoryImpl; + +/** + * A set of Utilities to serialize {@link Statement}s to/from {@link String}s. + */ +public class StatementSerializer { + private static String SEP = "\u0000"; + + private static ValueFactory VALUE_FACTORY = new ValueFactoryImpl(); + + /** + * Read a {@link Statement} from a {@link String} + * + * @param in + * the {@link String} to parse + * @return a {@link Statement} + */ + public static Statement readStatement(String in) throws IOException { + String[] parts = in.split(SEP); + + if (parts.length != 4) { + throw new IOException("Not a valid statement: " + in); + } + + String contextString = parts[0]; + String subjectString = parts[1]; + String predicateString = parts[2]; + String objectString = parts[3]; + return readStatement(subjectString, predicateString, objectString, contextString); + } + + public static Statement readStatement(String subjectString, String predicateString, String objectString) { + return readStatement(subjectString, predicateString, objectString, ""); + } + + public static Statement readStatement(String subjectString, String predicateString, String objectString, String contextString) { + Resource subject = createResource(subjectString); + URI predicate = VALUE_FACTORY.createURI(predicateString); + + boolean isObjectLiteral = objectString.startsWith("\""); + + Value object = null; + if (isObjectLiteral) { + object = parseLiteral(objectString); + } else { + object = createResource(objectString); + } + + if (contextString == null || contextString.isEmpty()) { + return new StatementImpl(subject, predicate, object); + } else { + Resource context = VALUE_FACTORY.createURI(contextString); + return new ContextStatementImpl(subject, predicate, object, context); + } + } + + private static Resource createResource(String str) { + if (str.startsWith("_")) { + return VALUE_FACTORY.createBNode(str.substring(2)); + } + return VALUE_FACTORY.createURI(str); + + } + + private static Literal parseLiteral(String fullLiteralString) { + Validate.notNull(fullLiteralString); + Validate.isTrue(fullLiteralString.length() > 1); + + if (fullLiteralString.endsWith("\"")) { + String fullLiteralWithoutQuotes = fullLiteralString.substring(1, fullLiteralString.length() - 1); + return VALUE_FACTORY.createLiteral(fullLiteralWithoutQuotes, (String) null); + } else { + + // find the closing quote + int labelEnd = fullLiteralString.lastIndexOf("\""); + + String label = fullLiteralString.substring(1, labelEnd); + + String data = fullLiteralString.substring(labelEnd + 1); + + if (data.startsWith("@")) { + // the data is "language" + String lang = data.substring(1); + return VALUE_FACTORY.createLiteral(label, lang); + } else if (data.startsWith("^^<")) { + // the data is a "datatype" + String datatype = data.substring(3, data.length() - 1); + URI datatypeUri = VALUE_FACTORY.createURI(datatype); + return VALUE_FACTORY.createLiteral(label, datatypeUri); + } + } + return null; + + } + + public static String writeSubject(Statement statement) { + return statement.getSubject().toString(); + } + + public static String writeObject(Statement statement) { + return statement.getObject().toString(); + } + + public static String writePredicate(Statement statement) { + return statement.getPredicate().toString(); + } + + public static String writeSubjectPredicate(Statement statement) { + Validate.notNull(statement); + Validate.notNull(statement.getSubject()); + Validate.notNull(statement.getPredicate()); + return statement.getSubject().toString() + SEP + statement.getPredicate().toString(); + } + + public static String writeContext(Statement statement) { + if (statement.getContext() == null) { + return ""; + } + return statement.getContext().toString(); + } + + /** + * Write a {@link Statement} to a {@link String} + * + * @param statement + * the {@link Statement} to write + * @return a {@link String} representation of the statement + */ + public static String writeStatement(Statement statement) { + Resource subject = statement.getSubject(); + Resource context = statement.getContext(); + URI predicate = statement.getPredicate(); + Value object = statement.getObject(); + + Validate.notNull(subject); + Validate.notNull(predicate); + Validate.notNull(object); + + String s = ""; + if (context == null) { + s = SEP + subject.toString() + SEP + predicate.toString() + SEP + object.toString(); + } else { + s = context.toString() + SEP + subject.toString() + SEP + predicate.toString() + SEP + object.toString(); + } + return s; + } + + /** + * Creates a Regular Expression to match serialized statements meeting these constraints. A <code>null</code> or empty parameters imply + * no constraint. A <code>null</code> return value implies no constraints. + * + * @param context + * context constraint + * @param subject + * subject constraint + * @param predicates + * list of predicate constraints + * @return a regular expression that can be used to match serialized statements. A <code>null</code> return value implies no + * constraints. + */ + public static String createStatementRegex(StatementConstraints contraints) { + Resource context = contraints.getContext(); + Resource subject = contraints.getSubject(); + Set<URI> predicates = contraints.getPredicates(); + if (context == null && subject == null && (predicates == null || predicates.isEmpty())) { + return null; + } + + // match on anything but a separator + String anyReg = "[^" + SEP + "]*"; + + // if context is empty, match on any context + String contextReg = (context == null) ? anyReg : context.stringValue(); + + // if subject is empty, match on any subject + String subjectReg = (subject == null) ? anyReg : subject.stringValue(); + + // if the predicates are empty, match on any predicate. Otherwise, "or" the predicates. + String predicateReg = ""; + if (predicates == null || predicates.isEmpty()) { + predicateReg = anyReg; + } else { + predicateReg = "(" + StringUtils.join(predicates, "|") + ")"; + } + + return "^" + contextReg + SEP + subjectReg + SEP + predicateReg + SEP + ".*"; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/917e7a57/extras/indexing/src/main/java/mvm/rya/indexing/TemporalIndexer.java ---------------------------------------------------------------------- diff --git a/extras/indexing/src/main/java/mvm/rya/indexing/TemporalIndexer.java b/extras/indexing/src/main/java/mvm/rya/indexing/TemporalIndexer.java index be06e25..3f6858c 100644 --- a/extras/indexing/src/main/java/mvm/rya/indexing/TemporalIndexer.java +++ b/extras/indexing/src/main/java/mvm/rya/indexing/TemporalIndexer.java @@ -1,5 +1,8 @@ package mvm.rya.indexing; +import org.openrdf.model.Statement; +import org.openrdf.query.QueryEvaluationException; + /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -8,9 +11,9 @@ package mvm.rya.indexing; * 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 @@ -21,53 +24,45 @@ package mvm.rya.indexing; import info.aduna.iteration.CloseableIteration; - -import java.io.IOException; -import java.util.Set; - import mvm.rya.api.persist.index.RyaSecondaryIndexer; -import org.openrdf.model.Statement; -import org.openrdf.model.URI; -import org.openrdf.query.QueryEvaluationException; - /** * A repository to store, index, and retrieve {@link Statement}s based on time. * Instants: * Instant {before, equals, after} Instant * Instant {before, after, inside} Interval * Instant {hasBeginning, hasEnd} Interval - * + * * OWL-Time provides the interval relations: * <pre> - * intervalEquals, - * intervalBefore, - * intervalMeets, - * intervalOverlaps, - * intervalStarts, - * intervalDuring, - * intervalFinishes, - * - * and their reverse interval relations: - * intervalAfter, - * intervalMetBy, - * intervalOverlappedBy, - * intervalStartedBy, - * intervalContains, + * intervalEquals, + * intervalBefore, + * intervalMeets, + * intervalOverlaps, + * intervalStarts, + * intervalDuring, + * intervalFinishes, + * + * and their reverse interval relations: + * intervalAfter, + * intervalMetBy, + * intervalOverlappedBy, + * intervalStartedBy, + * intervalContains, * intervalFinishedBy. - * - * from Allen paper in 1983 - * + * + * from Allen paper in 1983 + * * Relation Y Symbol Inverse Y - * before Y < > X - * equal Y = = X + * before Y < > X + * equal Y = = X * meets Y m mi X - * overlaps Y o oi X - * during Y d di X - * starts Y s si X + * overlaps Y o oi X + * during Y d di X + * starts Y s si X * finishes Y f fi X * </pre> - * + * */ public interface TemporalIndexer extends RyaSecondaryIndexer { @@ -75,109 +70,97 @@ public interface TemporalIndexer extends RyaSecondaryIndexer { /* consider ParseException here */ /*- - * - * And Now, what you you've all been waiting for, the queries: + * + * And Now, what you you've all been waiting for, the queries: * the instant versions: * format: x {relation} y * read: Given literal y, find all statements where the date object x is ( x relation y ) * Instant {before, equals, after} Instant * Instant {before, after, inside} Interval * Instant {hasBeginning, hasEnd} Interval - * - * the Allen interval relations, as described above. - * intervalEquals, - * intervalBefore, - * intervalMeets, - * intervalOverlaps, - * intervalStarts, - * intervalDuring, + * + * the Allen interval relations, as described above. + * intervalEquals, + * intervalBefore, + * intervalMeets, + * intervalOverlaps, + * intervalStarts, + * intervalDuring, * intervalFinishes * and then the inverses, including after. */ public abstract CloseableIteration<Statement, QueryEvaluationException> queryInstantEqualsInstant( - TemporalInstant queryInstant, StatementContraints contraints) + TemporalInstant queryInstant, StatementConstraints contraints) throws QueryEvaluationException;; public abstract CloseableIteration<Statement, QueryEvaluationException> queryInstantBeforeInstant( - TemporalInstant queryInstant, StatementContraints contraints) + TemporalInstant queryInstant, StatementConstraints contraints) throws QueryEvaluationException;; public abstract CloseableIteration<Statement, QueryEvaluationException> queryInstantAfterInstant( - TemporalInstant queryInstant, StatementContraints contraints) + TemporalInstant queryInstant, StatementConstraints contraints) throws QueryEvaluationException;; public abstract CloseableIteration<Statement, QueryEvaluationException> queryInstantBeforeInterval( - TemporalInterval givenInterval, StatementContraints contraints) + TemporalInterval givenInterval, StatementConstraints contraints) throws QueryEvaluationException;; public abstract CloseableIteration<Statement, QueryEvaluationException> queryInstantAfterInterval( - TemporalInterval givenInterval, StatementContraints contraints) + TemporalInterval givenInterval, StatementConstraints contraints) throws QueryEvaluationException; public abstract CloseableIteration<Statement, QueryEvaluationException> queryInstantInsideInterval( - TemporalInterval givenInterval, StatementContraints contraints) + TemporalInterval givenInterval, StatementConstraints contraints) throws QueryEvaluationException; public abstract CloseableIteration<Statement, QueryEvaluationException> queryInstantHasBeginningInterval( - TemporalInterval queryInterval, StatementContraints contraints) + TemporalInterval queryInterval, StatementConstraints contraints) throws QueryEvaluationException; public abstract CloseableIteration<Statement, QueryEvaluationException> queryInstantHasEndInterval( - TemporalInterval queryInterval, StatementContraints contraints) + TemporalInterval queryInterval, StatementConstraints contraints) throws QueryEvaluationException; /** * Returns statements that contain a time instance that is equal to the - * queried time and meet the {@link StatementContraints}. - * + * queried time and meet the {@link StatementConstraints}. + * * @param query * the queried time instance * @param contraints - * the {@link StatementContraints} + * the {@link StatementConstraints} * @return * @throws QueryEvaluationException */ public abstract CloseableIteration<Statement, QueryEvaluationException> queryIntervalEquals( - TemporalInterval query, StatementContraints contraints) + TemporalInterval query, StatementConstraints contraints) throws QueryEvaluationException; /** * Returns statements that contain a time instances that are before the - * queried {@link TemporalInterval} and meet the {@link StatementContraints} - * + * queried {@link TemporalInterval} and meet the {@link StatementConstraints} + * * @param query * the queried time instance * @param contraints - * the {@link StatementContraints} + * the {@link StatementConstraints} * @return */ public abstract CloseableIteration<Statement, QueryEvaluationException> queryIntervalBefore( - TemporalInterval query, StatementContraints contraints) + TemporalInterval query, StatementConstraints contraints) throws QueryEvaluationException; /** - * Returns statements that contain a time instance that is after the queried {@link TemporalInterval} and meet the {@link StatementContraints}. + * Returns statements that contain a time instance that is after the queried {@link TemporalInterval} and meet the {@link StatementConstraints}. * * @param query * the queried time instance * @param contraints - * the {@link StatementContraints} + * the {@link StatementConstraints} * @return */ public abstract CloseableIteration<Statement, QueryEvaluationException> queryIntervalAfter( - TemporalInterval query, StatementContraints contraints) + TemporalInterval query, StatementConstraints contraints) throws QueryEvaluationException; - - /* End of the Allen algebra queries */ - /** - * @return the set of predicates indexed by the indexer. - */ - public abstract Set<URI> getIndexablePredicates(); - - @Override - public abstract void flush() throws IOException; - - @Override - public abstract void close() throws IOException; } http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/917e7a57/extras/indexing/src/main/java/mvm/rya/indexing/TemporalInstantRfc3339.java ---------------------------------------------------------------------- diff --git a/extras/indexing/src/main/java/mvm/rya/indexing/TemporalInstantRfc3339.java b/extras/indexing/src/main/java/mvm/rya/indexing/TemporalInstantRfc3339.java new file mode 100644 index 0000000..f47bb92 --- /dev/null +++ b/extras/indexing/src/main/java/mvm/rya/indexing/TemporalInstantRfc3339.java @@ -0,0 +1,219 @@ +/** + * + */ +package mvm.rya.indexing; + +/* + * 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. + */ + + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.codec.binary.StringUtils; +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; + +/** + * Immutable date and time instance returning a human readable key. + * Preserves the Time zone, but not stored in the key. + * Converts fields (hours, etc) correctly for tz=Zulu when stored, + * so the original timezone is not preserved when retrieved. + * + * Uses rfc 3339, which looks like: YYYY-MM-DDThh:mm:ssZ a subset + * of ISO-8601 : https://www.ietf.org/rfc/rfc3339.txt + * + * Limits: All dates and times are assumed to be in the "current era", no BC, + * somewhere between 0000AD and 9999AD. + * + * Resolution: to the second, or millisecond if the optional fraction is used. + * + * This is really a wrapper for Joda DateTime. if you need functionality from + * that wonderful class, simply use t.getAsDateTime(). + * + */ +public class TemporalInstantRfc3339 implements TemporalInstant { + + private static final long serialVersionUID = -7790000399142290309L; + + private final DateTime dateTime; + /** + * Format key like this: YYYY-MM-DDThh:mm:ssZ + */ + public final static DateTimeFormatter FORMATTER = ISODateTimeFormat.dateTimeNoMillis(); + + public static final Pattern PATTERN = Pattern.compile("\\[(.*)\\,(.*)\\].*"); + + /** + * New date assumed UTC time zone. + * + * @param year + * @param month + * @param day + * @param hour + * @param minute + * @param second + */ + public TemporalInstantRfc3339(final int year, final int month, final int day, final int hour, final int minute, final int second) { + dateTime = new DateTime(year, month, day, hour, minute, second, DateTimeZone.UTC); + } + + /** + * Construct with a Joda/java v8 DateTime; + * TZ is preserved, but not in the key. + * + * @param dateTime + * initialize with this date time. Converted to zulu time zone for key generation. + * @return + */ + public TemporalInstantRfc3339(final DateTime datetime) { + dateTime = datetime; + } + /** + * Get an interval setting beginning and end with this implementation of {@link TemporalInstant}. + * beginning must be less than end. + * + * @param dateTimeInterval String in the form [dateTime1,dateTime2] + */ + public static TemporalInterval parseInterval(final String dateTimeInterval) { + + final Matcher matcher = PATTERN.matcher(dateTimeInterval); + if (matcher.find()) { + // Got a date time pair, parse into an interval. + return new TemporalInterval( + new TemporalInstantRfc3339(new DateTime(matcher.group(1))), + new TemporalInstantRfc3339(new DateTime(matcher.group(2)))); + } + throw new IllegalArgumentException("Can't parse interval, expecting '[ISO8601dateTime1,ISO8601dateTime2]', actual: "+dateTimeInterval); + } + + /** + * if this is older returns -1, equal 0, else 1 + * + */ + @Override + public int compareTo(final TemporalInstant that) { + return getAsKeyString().compareTo(that.getAsKeyString()); + } + + @Override + public byte[] getAsKeyBytes() { + return StringUtils.getBytesUtf8(getAsKeyString()); + } + + @Override + public String getAsKeyString() { + return dateTime.withZone(DateTimeZone.UTC).toString(FORMATTER); + } + + /** + * Readable string, formated local time at {@link DateTimeZone}. + * If the timezone is UTC (Z), it was probably a key from the database. + * If the server and client are in different Time zone, should probably use the client timezone. + * + * Time at specified time zone: + * instant.getAsReadable(DateTimeZone.forID("-05:00"))); + * instant.getAsReadable(DateTimeZone.getDefault())); + * + * Use original time zone set in the constructor: + * instant.getAsDateTime().toString(TemporalInstantRfc3339.FORMATTER)); + * + */ + @Override + public String getAsReadable(final DateTimeZone dateTimeZone) { + return dateTime.withZone(dateTimeZone).toString(FORMATTER); + } + + /** + * Use original time zone set in the constructor, or UTC if from parsing the key. + */ + @Override + public String getAsReadable() { + return dateTime.toString(FORMATTER); + } + + /** + * default toString, same as getAsReadable(). + */ + @Override + public String toString() { + return getAsReadable(); + } + + /** + * Show readable time converted to the default timezone. + */ + @Override + public DateTime getAsDateTime() { + return dateTime; + } + + /** + * Minimum Date, used for infinitely past. + */ + private static final TemporalInstant MINIMUM = new TemporalInstantRfc3339(new DateTime(Long.MIN_VALUE)); + /** + * maximum date/time is used for infinitely in the future. + */ + private static final TemporalInstant MAXIMUM = new TemporalInstantRfc3339(new DateTime(Long.MAX_VALUE)); + + /** + * infinite past date. + * @return an instant that will compare as NEWER than anything but itself. + */ + public static TemporalInstant getMinimumInstance() { + return MINIMUM; + } + /** + * infinite future date. + * @return an instant that will compare as OLDER than anything but itself + */ + + public static TemporalInstant getMaximumInstance() { + return MAXIMUM; + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return getAsKeyString().hashCode(); + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final TemporalInstantRfc3339 other = (TemporalInstantRfc3339) obj; + return (getAsKeyString().equals(other.getAsKeyString())); + } +} http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/917e7a57/extras/indexing/src/main/java/mvm/rya/indexing/TemporalTupleSet.java ---------------------------------------------------------------------- diff --git a/extras/indexing/src/main/java/mvm/rya/indexing/TemporalTupleSet.java b/extras/indexing/src/main/java/mvm/rya/indexing/TemporalTupleSet.java new file mode 100644 index 0000000..1677fed --- /dev/null +++ b/extras/indexing/src/main/java/mvm/rya/indexing/TemporalTupleSet.java @@ -0,0 +1,287 @@ +package mvm.rya.indexing; + +import java.util.Map; +import java.util.Set; + +import org.apache.hadoop.conf.Configuration; +import org.joda.time.DateTime; +import org.openrdf.model.Statement; +import org.openrdf.model.URI; +import org.openrdf.model.impl.URIImpl; +import org.openrdf.query.BindingSet; +import org.openrdf.query.QueryEvaluationException; +import org.openrdf.query.algebra.QueryModelVisitor; + +import com.google.common.base.Joiner; +import com.google.common.collect.Maps; + +/* + * 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. + */ + +import info.aduna.iteration.CloseableIteration; +import mvm.rya.indexing.external.tupleSet.ExternalTupleSet; + +//Indexing Node for temporal expressions to be inserted into execution plan +//to delegate temporal portion of query to temporal index +public class TemporalTupleSet extends ExternalTupleSet { + + private final Configuration conf; + private final TemporalIndexer temporalIndexer; + private final IndexingExpr filterInfo; + + public TemporalTupleSet(final IndexingExpr filterInfo, final TemporalIndexer temporalIndexer) { + this.filterInfo = filterInfo; + this.temporalIndexer = temporalIndexer; + conf = temporalIndexer.getConf(); + } + + /** + * {@inheritDoc} + */ + @Override + public Set<String> getBindingNames() { + return filterInfo.getBindingNames(); + } + + /** + * {@inheritDoc} + * <p> + * Note that we need a deep copy for everything that (during optimizations) + * can be altered via {@link #visitChildren(QueryModelVisitor)} + */ + @Override + public TemporalTupleSet clone() { + return new TemporalTupleSet(filterInfo, temporalIndexer); + } + + @Override + public double cardinality() { + return 0.0; // No idea how the estimate cardinality here. + } + + @Override + public String getSignature() { + + return "(TemporalTuple Projection) " + "variables: " + Joiner.on(", ").join(getBindingNames()).replaceAll("\\s+", " "); + } + + @Override + public boolean equals(final Object other) { + if (other == this) { + return true; + } + if (!(other instanceof TemporalTupleSet)) { + return false; + } + final TemporalTupleSet arg = (TemporalTupleSet) other; + return filterInfo.equals(arg.filterInfo); + } + + @Override + public int hashCode() { + int result = 17; + result = 31*result + filterInfo.hashCode(); + + return result; + } + + /** + * Returns an iterator over the result set associated with contained IndexingExpr. + * <p> + * Should be thread-safe (concurrent invocation {@link OfflineIterable} this + * method can be expected with some query evaluators. + */ + @Override + public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(final BindingSet bindings) + throws QueryEvaluationException { + final URI funcURI = filterInfo.getFunction(); + final SearchFunction searchFunction = (new TemporalSearchFunctionFactory(conf)).getSearchFunction(funcURI); + + if(filterInfo.getArguments().length > 1) { + throw new IllegalArgumentException("Index functions do not support more than two arguments."); + } + + final String queryText = filterInfo.getArguments()[0].stringValue(); + return IteratorFactory.getIterator(filterInfo.getSpConstraint(), bindings, queryText, searchFunction); + } + + //returns appropriate search function for a given URI + //search functions used by TemporalIndexer to query Temporal Index + private class TemporalSearchFunctionFactory { + private final Map<URI, SearchFunction> SEARCH_FUNCTION_MAP = Maps.newHashMap(); + Configuration conf; + + public TemporalSearchFunctionFactory(final Configuration conf) { + this.conf = conf; + } + + /** + * Get a {@link TemporalSearchFunction} for a give URI. + * + * @param searchFunction + * @return + */ + public SearchFunction getSearchFunction(final URI searchFunction) { + SearchFunction geoFunc = null; + try { + geoFunc = getSearchFunctionInternal(searchFunction); + } catch (final QueryEvaluationException e) { + e.printStackTrace(); + } + + return geoFunc; + } + + private SearchFunction getSearchFunctionInternal(final URI searchFunction) throws QueryEvaluationException { + final SearchFunction sf = SEARCH_FUNCTION_MAP.get(searchFunction); + + if (sf != null) { + return sf; + } else { + throw new QueryEvaluationException("Unknown Search Function: " + searchFunction.stringValue()); + } + } + + private final SearchFunction TEMPORAL_InstantAfterInstant = new SearchFunction() { + @Override + public CloseableIteration<Statement, QueryEvaluationException> performSearch(final String searchTerms, + final StatementConstraints contraints) throws QueryEvaluationException { + final TemporalInstant queryInstant = new TemporalInstantRfc3339(DateTime.parse(searchTerms)); + return temporalIndexer.queryInstantAfterInstant(queryInstant, contraints); + } + + @Override + public String toString() { + return "TEMPORAL_InstantAfterInstant"; + }; + }; + private final SearchFunction TEMPORAL_InstantBeforeInstant = new SearchFunction() { + @Override + public CloseableIteration<Statement, QueryEvaluationException> performSearch(final String searchTerms, + final StatementConstraints contraints) throws QueryEvaluationException { + final TemporalInstant queryInstant = new TemporalInstantRfc3339(DateTime.parse(searchTerms)); + return temporalIndexer.queryInstantBeforeInstant(queryInstant, contraints); + } + + @Override + public String toString() { + return "TEMPORAL_InstantBeforeInstant"; + }; + }; + + private final SearchFunction TEMPORAL_InstantEqualsInstant = new SearchFunction() { + @Override + public CloseableIteration<Statement, QueryEvaluationException> performSearch(final String searchTerms, + final StatementConstraints contraints) throws QueryEvaluationException { + final TemporalInstant queryInstant = new TemporalInstantRfc3339(DateTime.parse(searchTerms)); + return temporalIndexer.queryInstantEqualsInstant(queryInstant, contraints); + } + + @Override + public String toString() { + return "TEMPORAL_InstantEqualsInstant"; + }; + }; + + private final SearchFunction TEMPORAL_InstantAfterInterval = new SearchFunction() { + @Override + public CloseableIteration<Statement, QueryEvaluationException> performSearch(final String searchTerms, + final StatementConstraints contraints) throws QueryEvaluationException { + final TemporalInterval queryInterval = TemporalInstantRfc3339.parseInterval(searchTerms); + return temporalIndexer.queryInstantAfterInterval(queryInterval, contraints); + } + + @Override + public String toString() { + return "TEMPORAL_InstantAfterInterval"; + }; + }; + + private final SearchFunction TEMPORAL_InstantBeforeInterval = new SearchFunction() { + @Override + public CloseableIteration<Statement, QueryEvaluationException> performSearch(final String searchTerms, + final StatementConstraints contraints) throws QueryEvaluationException { + final TemporalInterval queryInterval = TemporalInstantRfc3339.parseInterval(searchTerms); + return temporalIndexer.queryInstantBeforeInterval(queryInterval, contraints); + } + + @Override + public String toString() { + return "TEMPORAL_InstantBeforeInterval"; + }; + }; + + private final SearchFunction TEMPORAL_InstantInsideInterval = new SearchFunction() { + @Override + public CloseableIteration<Statement, QueryEvaluationException> performSearch(final String searchTerms, + final StatementConstraints contraints) throws QueryEvaluationException { + final TemporalInterval queryInterval = TemporalInstantRfc3339.parseInterval(searchTerms); + return temporalIndexer.queryInstantInsideInterval(queryInterval, contraints); + } + + @Override + public String toString() { + return "TEMPORAL_InstantInsideInterval"; + }; + }; + + private final SearchFunction TEMPORAL_InstantHasBeginningInterval = new SearchFunction() { + @Override + public CloseableIteration<Statement, QueryEvaluationException> performSearch(final String searchTerms, + final StatementConstraints contraints) throws QueryEvaluationException { + final TemporalInterval queryInterval = TemporalInstantRfc3339.parseInterval(searchTerms); + return temporalIndexer.queryInstantHasBeginningInterval(queryInterval, contraints); + } + + @Override + public String toString() { + return "TEMPORAL_InstantHasBeginningInterval"; + }; + }; + + private final SearchFunction TEMPORAL_InstantHasEndInterval = new SearchFunction() { + @Override + public CloseableIteration<Statement, QueryEvaluationException> performSearch(final String searchTerms, + final StatementConstraints contraints) throws QueryEvaluationException { + final TemporalInterval queryInterval = TemporalInstantRfc3339.parseInterval(searchTerms); + return temporalIndexer.queryInstantHasEndInterval(queryInterval, contraints); + } + + @Override + public String toString() { + return "TEMPORAL_InstantHasEndInterval"; + }; + }; + + { + final String TEMPORAL_NS = "tag:rya-rdf.org,2015:temporal#"; + + SEARCH_FUNCTION_MAP.put(new URIImpl(TEMPORAL_NS+"after"), TEMPORAL_InstantAfterInstant); + SEARCH_FUNCTION_MAP.put(new URIImpl(TEMPORAL_NS+"before"), TEMPORAL_InstantBeforeInstant); + SEARCH_FUNCTION_MAP.put(new URIImpl(TEMPORAL_NS+"equals"), TEMPORAL_InstantEqualsInstant); + + SEARCH_FUNCTION_MAP.put(new URIImpl(TEMPORAL_NS+"beforeInterval"), TEMPORAL_InstantBeforeInterval); + SEARCH_FUNCTION_MAP.put(new URIImpl(TEMPORAL_NS+"afterInterval"), TEMPORAL_InstantAfterInterval); + SEARCH_FUNCTION_MAP.put(new URIImpl(TEMPORAL_NS+"insideInterval"), TEMPORAL_InstantInsideInterval); + SEARCH_FUNCTION_MAP.put(new URIImpl(TEMPORAL_NS+"hasBeginningInterval"), + TEMPORAL_InstantHasBeginningInterval); + SEARCH_FUNCTION_MAP.put(new URIImpl(TEMPORAL_NS+"hasEndInterval"), TEMPORAL_InstantHasEndInterval); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/917e7a57/extras/indexing/src/main/java/mvm/rya/indexing/accumulo/ConfigUtils.java ---------------------------------------------------------------------- diff --git a/extras/indexing/src/main/java/mvm/rya/indexing/accumulo/ConfigUtils.java b/extras/indexing/src/main/java/mvm/rya/indexing/accumulo/ConfigUtils.java index 1b92117..3dce3a2 100644 --- a/extras/indexing/src/main/java/mvm/rya/indexing/accumulo/ConfigUtils.java +++ b/extras/indexing/src/main/java/mvm/rya/indexing/accumulo/ConfigUtils.java @@ -35,9 +35,9 @@ import mvm.rya.indexing.accumulo.freetext.LuceneTokenizer; import mvm.rya.indexing.accumulo.freetext.Tokenizer; import mvm.rya.indexing.accumulo.geo.GeoMesaGeoIndexer; import mvm.rya.indexing.accumulo.temporal.AccumuloTemporalIndexer; -import mvm.rya.indexing.mongodb.MongoFreeTextIndexer; -import mvm.rya.indexing.mongodb.MongoGeoIndexer; -import mvm.rya.indexing.pcj.matching.PCJOptimizer; +import mvm.rya.indexing.external.PrecompJoinOptimizer; +import mvm.rya.indexing.mongodb.freetext.MongoFreeTextIndexer; +import mvm.rya.indexing.mongodb.geo.MongoGeoIndexer; import org.apache.accumulo.core.client.AccumuloException; import org.apache.accumulo.core.client.AccumuloSecurityException; @@ -157,7 +157,7 @@ public class ConfigUtils { return false; } - private static String getIndexTableName(Configuration conf, String indexTableNameConf, String altSuffix){ + private static String getIndexTableName(final Configuration conf, final String indexTableNameConf, final String altSuffix){ String value = conf.get(indexTableNameConf); if (value == null){ final String defaultTableName = conf.get(RdfCloudTripleStoreConfiguration.CONF_TBL_PREFIX); @@ -183,12 +183,12 @@ public class ConfigUtils { return getIndexTableName(conf, GEO_TABLENAME, "geo"); } - public static String getTemporalTableName(Configuration conf) { + public static String getTemporalTableName(final Configuration conf) { return getIndexTableName(conf, TEMPORAL_TABLENAME, "temporal"); } - public static String getEntityTableName(Configuration conf) { + public static String getEntityTableName(final Configuration conf) { return getIndexTableName(conf, ENTITY_TABLENAME, "entity"); } @@ -342,39 +342,39 @@ public class ConfigUtils { return conf.getInt(GEO_NUM_PARTITIONS, getNumPartitions(conf)); } - public static boolean getUseGeo(Configuration conf) { + public static boolean getUseGeo(final Configuration conf) { return conf.getBoolean(USE_GEO, false); } - public static boolean getUseFreeText(Configuration conf) { + public static boolean getUseFreeText(final Configuration conf) { return conf.getBoolean(USE_FREETEXT, false); } - public static boolean getUseTemporal(Configuration conf) { + public static boolean getUseTemporal(final Configuration conf) { return conf.getBoolean(USE_TEMPORAL, false); } - public static boolean getUseEntity(Configuration conf) { + public static boolean getUseEntity(final Configuration conf) { return conf.getBoolean(USE_ENTITY, false); } - public static boolean getUsePCJ(Configuration conf) { + public static boolean getUsePCJ(final Configuration conf) { return conf.getBoolean(USE_PCJ, false); } - public static boolean getUseOptimalPCJ(Configuration conf) { + public static boolean getUseOptimalPCJ(final Configuration conf) { return conf.getBoolean(USE_OPTIMAL_PCJ, false); } - public static boolean getUseMongo(Configuration conf) { + public static boolean getUseMongo(final Configuration conf) { return conf.getBoolean(USE_MONGO, false); } - public static void setIndexers(RdfCloudTripleStoreConfiguration conf) { + public static void setIndexers(final RdfCloudTripleStoreConfiguration conf) { - List<String> indexList = Lists.newArrayList(); - List<String> optimizers = Lists.newArrayList(); + final List<String> indexList = Lists.newArrayList(); + final List<String> optimizers = Lists.newArrayList(); boolean useFilterIndex = false; @@ -390,7 +390,7 @@ public class ConfigUtils { } else { if (getUsePCJ(conf) || getUseOptimalPCJ(conf)) { - conf.setPcjOptimizer(PCJOptimizer.class); + conf.setPcjOptimizer(PrecompJoinOptimizer.class); } if (getUseGeo(conf)) { http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/917e7a57/extras/indexing/src/main/java/mvm/rya/indexing/accumulo/Md5Hash.java ---------------------------------------------------------------------- diff --git a/extras/indexing/src/main/java/mvm/rya/indexing/accumulo/Md5Hash.java b/extras/indexing/src/main/java/mvm/rya/indexing/accumulo/Md5Hash.java deleted file mode 100644 index 8fa3008..0000000 --- a/extras/indexing/src/main/java/mvm/rya/indexing/accumulo/Md5Hash.java +++ /dev/null @@ -1,45 +0,0 @@ -package mvm.rya.indexing.accumulo; - -/* - * 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. - */ - - - -import org.apache.accumulo.core.data.Value; -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.codec.binary.StringUtils; -import org.apache.commons.codec.digest.DigestUtils; - -/** - * Utility methods for generating hashes. Note that MD5 is 16 bytes, or 32 Hex chars. To make it smaller (but still printable), this class - * Base64 encodes those 16 bytes into 22 chars. - */ -public class Md5Hash { - public static String md5Base64(byte[] data) { - return Base64.encodeBase64URLSafeString(DigestUtils.md5(data)); - } - - public static String md5Base64(String string) { - return md5Base64(StringUtils.getBytesUtf8(string)); - } - - public static byte[] md5Binary(Value value) { - return DigestUtils.md5(value.get()); - } -} http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/917e7a57/extras/indexing/src/main/java/mvm/rya/indexing/accumulo/StatementSerializer.java ---------------------------------------------------------------------- diff --git a/extras/indexing/src/main/java/mvm/rya/indexing/accumulo/StatementSerializer.java b/extras/indexing/src/main/java/mvm/rya/indexing/accumulo/StatementSerializer.java deleted file mode 100644 index f5d6d0e..0000000 --- a/extras/indexing/src/main/java/mvm/rya/indexing/accumulo/StatementSerializer.java +++ /dev/null @@ -1,227 +0,0 @@ -package mvm.rya.indexing.accumulo; - -/* - * 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. - */ - - - -import java.io.IOException; -import java.util.Set; - -import mvm.rya.indexing.StatementContraints; - -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.Validate; -import org.openrdf.model.Literal; -import org.openrdf.model.Resource; -import org.openrdf.model.Statement; -import org.openrdf.model.URI; -import org.openrdf.model.Value; -import org.openrdf.model.ValueFactory; -import org.openrdf.model.impl.ContextStatementImpl; -import org.openrdf.model.impl.StatementImpl; -import org.openrdf.model.impl.ValueFactoryImpl; - -/** - * A set of Utilities to serialize {@link Statement}s to/from {@link String}s. - */ -public class StatementSerializer { - private static String SEP = "\u0000"; - - private static ValueFactory VALUE_FACTORY = new ValueFactoryImpl(); - - /** - * Read a {@link Statement} from a {@link String} - * - * @param in - * the {@link String} to parse - * @return a {@link Statement} - */ - public static Statement readStatement(String in) throws IOException { - String[] parts = in.split(SEP); - - if (parts.length != 4) { - throw new IOException("Not a valid statement: " + in); - } - - String contextString = parts[0]; - String subjectString = parts[1]; - String predicateString = parts[2]; - String objectString = parts[3]; - return readStatement(subjectString, predicateString, objectString, contextString); - } - - public static Statement readStatement(String subjectString, String predicateString, String objectString) { - return readStatement(subjectString, predicateString, objectString, ""); - } - - public static Statement readStatement(String subjectString, String predicateString, String objectString, String contextString) { - Resource subject = createResource(subjectString); - URI predicate = VALUE_FACTORY.createURI(predicateString); - - boolean isObjectLiteral = objectString.startsWith("\""); - - Value object = null; - if (isObjectLiteral) { - object = parseLiteral(objectString); - } else { - object = createResource(objectString); - } - - if (contextString == null || contextString.isEmpty()) { - return new StatementImpl(subject, predicate, object); - } else { - Resource context = VALUE_FACTORY.createURI(contextString); - return new ContextStatementImpl(subject, predicate, object, context); - } - } - - private static Resource createResource(String str) { - if (str.startsWith("_")) { - return VALUE_FACTORY.createBNode(str.substring(2)); - } - return VALUE_FACTORY.createURI(str); - - } - - private static Literal parseLiteral(String fullLiteralString) { - Validate.notNull(fullLiteralString); - Validate.isTrue(fullLiteralString.length() > 1); - - if (fullLiteralString.endsWith("\"")) { - String fullLiteralWithoutQuotes = fullLiteralString.substring(1, fullLiteralString.length() - 1); - return VALUE_FACTORY.createLiteral(fullLiteralWithoutQuotes, (String) null); - } else { - - // find the closing quote - int labelEnd = fullLiteralString.lastIndexOf("\""); - - String label = fullLiteralString.substring(1, labelEnd); - - String data = fullLiteralString.substring(labelEnd + 1); - - if (data.startsWith("@")) { - // the data is "language" - String lang = data.substring(1); - return VALUE_FACTORY.createLiteral(label, lang); - } else if (data.startsWith("^^<")) { - // the data is a "datatype" - String datatype = data.substring(3, data.length() - 1); - URI datatypeUri = VALUE_FACTORY.createURI(datatype); - return VALUE_FACTORY.createLiteral(label, datatypeUri); - } - } - return null; - - } - - public static String writeSubject(Statement statement) { - return statement.getSubject().toString(); - } - - public static String writeObject(Statement statement) { - return statement.getObject().toString(); - } - - public static String writePredicate(Statement statement) { - return statement.getPredicate().toString(); - } - - public static String writeSubjectPredicate(Statement statement) { - Validate.notNull(statement); - Validate.notNull(statement.getSubject()); - Validate.notNull(statement.getPredicate()); - return statement.getSubject().toString() + SEP + statement.getPredicate().toString(); - } - - public static String writeContext(Statement statement) { - if (statement.getContext() == null) { - return ""; - } - return statement.getContext().toString(); - } - - /** - * Write a {@link Statement} to a {@link String} - * - * @param statement - * the {@link Statement} to write - * @return a {@link String} representation of the statement - */ - public static String writeStatement(Statement statement) { - Resource subject = statement.getSubject(); - Resource context = statement.getContext(); - URI predicate = statement.getPredicate(); - Value object = statement.getObject(); - - Validate.notNull(subject); - Validate.notNull(predicate); - Validate.notNull(object); - - String s = ""; - if (context == null) { - s = SEP + subject.toString() + SEP + predicate.toString() + SEP + object.toString(); - } else { - s = context.toString() + SEP + subject.toString() + SEP + predicate.toString() + SEP + object.toString(); - } - return s; - } - - /** - * Creates a Regular Expression to match serialized statements meeting these constraints. A <code>null</code> or empty parameters imply - * no constraint. A <code>null</code> return value implies no constraints. - * - * @param context - * context constraint - * @param subject - * subject constraint - * @param predicates - * list of predicate constraints - * @return a regular expression that can be used to match serialized statements. A <code>null</code> return value implies no - * constraints. - */ - public static String createStatementRegex(StatementContraints contraints) { - Resource context = contraints.getContext(); - Resource subject = contraints.getSubject(); - Set<URI> predicates = contraints.getPredicates(); - if (context == null && subject == null && (predicates == null || predicates.isEmpty())) { - return null; - } - - // match on anything but a separator - String anyReg = "[^" + SEP + "]*"; - - // if context is empty, match on any context - String contextReg = (context == null) ? anyReg : context.stringValue(); - - // if subject is empty, match on any subject - String subjectReg = (subject == null) ? anyReg : subject.stringValue(); - - // if the predicates are empty, match on any predicate. Otherwise, "or" the predicates. - String predicateReg = ""; - if (predicates == null || predicates.isEmpty()) { - predicateReg = anyReg; - } else { - predicateReg = "(" + StringUtils.join(predicates, "|") + ")"; - } - - return "^" + contextReg + SEP + subjectReg + SEP + predicateReg + SEP + ".*"; - } - -}
