package org.aksw.jena_sparql_api.core.utils; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.aksw.commons.collections.SetUtils; import org.aksw.commons.collections.diff.Diff; import org.aksw.jena_sparql_api.core.QuadContainmentChecker; import org.aksw.jena_sparql_api.core.QueryExecutionFactory; import org.aksw.jena_sparql_api.utils.DatasetGraphDiffUtils; import org.aksw.jena_sparql_api.utils.GraphUtils; import org.aksw.jena_sparql_api.utils.QuadPatternUtils; import org.aksw.jena_sparql_api.utils.QuadUtils; import org.aksw.jena_sparql_api.utils.QueryUtils; import org.aksw.jena_sparql_api.utils.ResultSetUtils; import org.aksw.jena_sparql_api.utils.SetDatasetGraph; import com.google.common.collect.Iterables; import com.google.common.collect.Iterators; import com.google.common.collect.Sets; import org.apache.jena.graph.Node; import org.apache.jena.query.Query; import org.apache.jena.query.QueryExecution; import org.apache.jena.sparql.core.BasicPattern; import org.apache.jena.sparql.core.DatasetGraph; import org.apache.jena.sparql.core.DatasetGraphFactory; import org.apache.jena.sparql.core.Quad; import org.apache.jena.sparql.engine.binding.Binding; import org.apache.jena.sparql.modify.request.QuadAcc; import org.apache.jena.sparql.modify.request.UpdateDataDelete; import org.apache.jena.sparql.modify.request.UpdateDataInsert; import org.apache.jena.sparql.modify.request.UpdateDeleteWhere; import org.apache.jena.sparql.modify.request.UpdateModify; import org.apache.jena.sparql.syntax.Element; import org.apache.jena.update.Update; import org.apache.jena.util.iterator.ExtendedIterator; public class UpdateDiffUtils { public static Diff<DatasetGraph> combineDatasetGraph(Iterable<? extends Diff<? extends DatasetGraph>> diffs) { Diff<DatasetGraph> result = Diff.create(DatasetGraphFactory.createMem(), DatasetGraphFactory.createMem()); // Create a writable view on the result Diff<Set<Quad>> resultView = DatasetGraphDiffUtils.wrapDatasetGraph(result); for(Diff<? extends DatasetGraph> diff : diffs) { Diff<Set<Quad>> itemView = DatasetGraphDiffUtils.wrapDatasetGraph(diff); combine(resultView, itemView); } return result; } public static <T> void combine(Diff<? extends Collection<T>> target, Diff<? extends Iterable<T>> source) { Iterables.addAll(target.getAdded(), source.getAdded()); Iterables.addAll(target.getRemoved(), source.getRemoved()); } public static Diff<Set<Quad>> combineIterables(Iterable<? extends Diff<? extends Iterable<Quad>>> diffs) { Diff<Set<Quad>> result = Diff.<Set<Quad>>create(new HashSet<Quad>(), new HashSet<Quad>()); for(Diff<? extends Iterable<Quad>> diff : diffs) { combine(result, diff); } return result; } public static Diff<Set<Quad>> makeUnique(Diff<? extends Iterable<Quad>> diff, QueryExecutionFactory qef, QuadContainmentChecker quadContainmentChecker) { Set<Quad> added = SetUtils.asSet(diff.getAdded()); Set<Quad> removed = SetUtils.asSet(diff.getRemoved()); added = added == null ? Collections.<Quad>emptySet() : added; removed = removed == null ? Collections.<Quad>emptySet() : removed; Set<Quad> toCheck = new HashSet<Quad>(); toCheck.addAll(added); toCheck.addAll(removed); Set<Quad> containedQuads = quadContainmentChecker.contains(qef, toCheck); Set<Quad> actualAdded = Sets.difference(added, containedQuads); // added minus containedQuads Set<Quad> actualRemoved = Sets.intersection(removed, containedQuads); // removed intersected with containedQuads Diff<Set<Quad>> result = new Diff<Set<Quad>>(actualAdded, actualRemoved, null); return result; } public static Iterator<Diff<Set<Quad>>> createIteratorDiff(QueryExecutionFactory qef, Update update, int batchSize) { Iterator<Diff<Set<Quad>>> result; if(update instanceof UpdateModify) { result = createIteratorDiff(qef, (UpdateModify)update, batchSize); } else if(update instanceof UpdateDataInsert) { result = createIteratorDiff(qef, (UpdateDataInsert)update); } else if(update instanceof UpdateDataDelete) { result = createIteratorDiff(qef, (UpdateDataDelete)update); } else if(update instanceof UpdateDeleteWhere) { result = createIteratorDiff(qef, (UpdateDeleteWhere)update, batchSize); } else { throw new RuntimeException("Unsupported update type: " + update.getClass()); } return result; } public static Iterator<Diff<Set<Quad>>> createIteratorDiff(QueryExecutionFactory qef, UpdateDeleteWhere update, int batchSize) { UpdateModify tmp = new UpdateModify(); QuadAcc acc = tmp.getDeleteAcc(); for(Quad quad : update.getQuads()) { acc.addQuad(quad); } Element element = QuadUtils.toElement(acc.getQuads()); tmp.setElement(element); Iterator<Diff<Set<Quad>>> result = createIteratorDiff(qef, tmp, batchSize); return result; } public static Iterator<Diff<Set<Quad>>> createIteratorDiff(QueryExecutionFactory qef, UpdateModify update, int batchSize) { Element wherePattern = update.getWherePattern(); Query query = QueryUtils.elementToQuery(wherePattern); // TODO Limit and offset... QueryExecution qe = qef.createQueryExecution(query); ExtendedIterator<Binding> itBinding = ResultSetUtils.toIteratorBinding(qe); Iterator<List<Binding>> itBindingChunk = Iterators.partition(itBinding, batchSize); Diff<List<Quad>> template = new Diff<List<Quad>>(update.getInsertQuads(), update.getDeleteQuads(), null); Iterator<Diff<Set<Quad>>> result = createIteratorDiff(itBindingChunk, template); //QuadDiffIterator result = new QuadDiffIterator(itBindingChunk, template); return result; } public static Iterator<Diff<Set<Quad>>> createIteratorDiff(QueryExecutionFactory qef, UpdateDataInsert update) { Diff<Set<Quad>> diff = new Diff<Set<Quad>>(Sets.newHashSet(update.getQuads()), Sets.<Quad>newHashSet(), null); Iterator<Diff<Set<Quad>>> result = Collections.singleton(diff).iterator(); return result; } public static Iterator<Diff<Set<Quad>>> createIteratorDiff(QueryExecutionFactory qef, UpdateDataDelete update) { Diff<Set<Quad>> diff = new Diff<Set<Quad>>(Sets.<Quad>newHashSet(), Sets.newHashSet(update.getQuads()), null); Iterator<Diff<Set<Quad>>> result = Collections.singleton(diff).iterator(); return result; } public static Iterator<Diff<Set<Quad>>> createIteratorDiff(Iterator<? extends Iterable<? extends Binding>> itBindings, Diff<? extends Iterable<Quad>> quadDiff) { FN_DiffFromBindings fn = FN_DiffFromBindings.create(quadDiff); Iterator<Diff<Set<Quad>>> result = Iterators.transform(itBindings, fn); return result; } public static Diff<Set<Quad>> buildDiff(Iterable<? extends Binding> bindings, Diff<? extends Iterable<Quad>> quadDiff) { Set<Quad> inserts = new HashSet<Quad>(); Set<Quad> deletes = new HashSet<Quad>(); for(Binding binding : bindings) { Set<Quad> i = QueryUtils.instanciate(quadDiff.getAdded(), binding); Set<Quad> d = QueryUtils.instanciate(quadDiff.getRemoved(), binding); inserts.addAll(i); deletes.addAll(d); // TODO Deal with overlaps } Diff<Set<Quad>> result = new Diff<Set<Quad>>(inserts, deletes, null); return result; } public static Diff<Set<Quad>> computeDelta(DatasetGraph after, DatasetGraph before) { SetDatasetGraph afterSet = new SetDatasetGraph(after); SetDatasetGraph beforeSet = new SetDatasetGraph(before); Diff<Set<Quad>> result = computeDelta(afterSet, beforeSet); return result; } public static Diff<Set<Quad>> computeDelta(Set<Quad> after, Set<Quad> before) { Set<Quad> actualAdded = Sets.difference(after, before); Set<Quad> actualRemoved = Sets.difference(before, after); Diff<Set<Quad>> result = new Diff<Set<Quad>>(actualAdded, actualRemoved, null); return result; } }