Smalyshev has uploaded a new change for review.
https://gerrit.wikimedia.org/r/204225
Change subject: WIP: change how values/refs are handled
......................................................................
WIP: change how values/refs are handled
Change-Id: I0397dc10fb7fbaf0d11433c31728ed8e28f58d84
---
M tools/src/main/java/org/wikidata/query/rdf/tool/Update.java
A tools/src/main/java/org/wikidata/query/rdf/tool/rdf/CleanUnused.sync.sparql
A tools/src/main/java/org/wikidata/query/rdf/tool/rdf/GetRefs.sync.sparql
A tools/src/main/java/org/wikidata/query/rdf/tool/rdf/GetValues.sync.sparql
M tools/src/main/java/org/wikidata/query/rdf/tool/rdf/Munger.java
M tools/src/main/java/org/wikidata/query/rdf/tool/rdf/RdfRepository.java
M tools/src/main/java/org/wikidata/query/rdf/tool/rdf/RdfRepository.sync.sparql
M tools/src/main/java/org/wikidata/query/rdf/tool/rdf/UpdateBuilder.java
8 files changed, 185 insertions(+), 89 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/wikidata/query/rdf
refs/changes/25/204225/1
diff --git a/tools/src/main/java/org/wikidata/query/rdf/tool/Update.java
b/tools/src/main/java/org/wikidata/query/rdf/tool/Update.java
index 012ebab..5f82268 100644
--- a/tools/src/main/java/org/wikidata/query/rdf/tool/Update.java
+++ b/tools/src/main/java/org/wikidata/query/rdf/tool/Update.java
@@ -251,9 +251,15 @@
log.debug("RDF repository already has this revision, skipping.");
return;
}
- Collection<Statement> statements =
wikibase.fetchRdfForEntity(change.entityId());
- munger.munge(change.entityId(), statements);
- rdfRepository.sync(change.entityId(), statements);
+ String entityId = change.entityId();
+ Collection<Statement> statements =
wikibase.fetchRdfForEntity(entityId);
+ Collection<String> values = rdfRepository.getValues(entityId);
+ Collection<String> refs = rdfRepository.getRefs(entityId);
+ munger.munge(entityId, statements, values, refs);
+ rdfRepository.sync(entityId, statements);
+ List<String> cleanupList = new ArrayList<String>(values);
+ cleanupList.addAll(refs);
+ rdfRepository.cleanUnused(cleanupList);
updateMeter.mark();
}
diff --git
a/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/CleanUnused.sync.sparql
b/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/CleanUnused.sync.sparql
new file mode 100644
index 0000000..edecc15
--- /dev/null
+++
b/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/CleanUnused.sync.sparql
@@ -0,0 +1,7 @@
+DELETE { ?s ?p ?o } WHERE {
+ VALUES ?s { %values% }
+ # Since values are shared we can only clear the values on them when they are
no longer used
+ # anywhere else.
+ FILTER NOT EXISTS { ?someEntity ?someStatementPred ?s . }
+ ?s ?p ?o .
+}
diff --git
a/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/GetRefs.sync.sparql
b/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/GetRefs.sync.sparql
new file mode 100644
index 0000000..cfb03b6
--- /dev/null
+++ b/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/GetRefs.sync.sparql
@@ -0,0 +1,6 @@
+SELECT DISTINCT ?s
+WHERE {
+ %entity:id% ?statementPred ?statement .
+ FILTER( STRSTARTS(STR(?statement), "%uris.statement%") ) .
+ ?statement %prov:wasDerivedFrom% ?s .
+}
diff --git
a/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/GetValues.sync.sparql
b/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/GetValues.sync.sparql
new file mode 100644
index 0000000..48ea9f9
--- /dev/null
+++ b/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/GetValues.sync.sparql
@@ -0,0 +1,13 @@
+SELECT DISTINCT ?s
+WHERE {
+ <http://www.wikidata.org/entity/Q30> ?statementPred ?statement .
+ FILTER( STRSTARTS(STR(?statement),
"http://www.wikidata.org/entity/statement/") ) .
+ ?statement <http://www.w3.org/ns/prov#wasDerivedFrom> ?s .
+ # Since references are shared we can only clear the values on them when they
are no longer used
+ # anywhere else.
+ FILTER NOT EXISTS {
+ ?otherStatement <http://www.w3.org/ns/prov#wasDerivedFrom> ?s .
+ ?otherEntity ?otherStatementPred ?otherStatement .
+ FILTER ( <http://www.wikidata.org/entity/Q23> != ?otherEntity ) .
+ }
+ ?s ?p ?o .
diff --git a/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/Munger.java
b/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/Munger.java
index fcf573d..5f9a32a 100644
--- a/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/Munger.java
+++ b/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/Munger.java
@@ -49,6 +49,14 @@
* True if we should remove site links or false if we shouldn't.
*/
private final boolean removeSiteLinks;
+ /**
+ * List of values connected to this entity
+ */
+ private Collection<String> valuesList;
+ /**
+ * List of refs connected to this entity
+ */
+ private Collection<String> refsList;
public Munger(WikibaseUris uris) {
this(uris, null, null, false);
@@ -112,15 +120,41 @@
* RDF exports into a more queryable form.
*
* @param statements statements to munge
+ * @param existingValues Existing value statements
+ * @param existingRefs Existing reference statements
*/
- public void munge(String entityId, Collection<Statement> statements)
throws ContainedException {
+ public void munge(String entityId, Collection<Statement> statements,
+ Collection<String> existingValues, Collection<String> existingRefs)
throws ContainedException {
+ if(existingValues == null) {
+ existingValues = new HashSet<String>();
+ }
+ if(existingRefs == null) {
+ existingRefs = new HashSet<String>();
+ }
+
if (statements.isEmpty()) {
// Empty collection is a delete.
return;
}
- MungeOperation op = new MungeOperation(entityId, statements);
+ MungeOperation op = new MungeOperation(entityId, statements,
existingValues, existingRefs);
op.munge();
+ // remove all values that we have seen as they are used by statements
+ existingValues.removeAll(op.extraValidSubjects);
+ existingRefs.removeAll(op.extraValidSubjects);
return;
+ }
+
+ public void munge(String entityId, Collection<Statement> statements) {
+ munge(entityId, statements, null, null);
+ }
+
+
+ public Collection<String> getValuesList() {
+ return valuesList;
+ }
+
+ public Collection<String> getRefsList() {
+ return refsList;
}
/**
@@ -174,7 +208,10 @@
private String subject;
private String predicate;
- public MungeOperation(String entityId, Collection<Statement>
statements) {
+ private final Collection<String> existingValues;
+ private final Collection<String> existingRefs;
+
+ public MungeOperation(String entityId, Collection<Statement>
statements, Collection<String> existingValues, Collection<String> existingRefs)
{
this.statements = statements;
entityUri = uris.entity() + entityId;
entityUriImpl = new URIImpl(entityUri);
@@ -185,6 +222,8 @@
singleLabelModeWorkForLabel = null;
singleLabelModeWorkForDescription = null;
}
+ this.existingValues = existingValues;
+ this.existingRefs = existingRefs;
}
public void munge() throws ContainedException {
@@ -348,17 +387,23 @@
* @return true to keep the statement, false to remove it
*/
private boolean entityReferenceStatement() throws ContainedException {
+ if(existingRefs.contains(subject)) {
+ /* We already have this ref, so no need to import it again
+ * Since refs are IDed by content, we know it is the same
+ */
+ return false;
+ }
switch (predicate) {
- case RDF.TYPE:
- /*
- * We don't need r:<uuid> a ontology:Reference because its
super
- * common and not super interesting.
- */
- if
(statement.getObject().stringValue().equals(Ontology.REFERENCE)) {
- return false;
- }
- break;
- default:
+ case RDF.TYPE:
+ /*
+ * We don't need r:<uuid> a ontology:Reference because its
super
+ * common and not super interesting.
+ */
+ if
(statement.getObject().stringValue().equals(Ontology.REFERENCE)) {
+ return false;
+ }
+ break;
+ default:
}
if (!extraValidSubjects.contains(subject)) {
/*
@@ -383,6 +428,12 @@
* @return true to keep the statement, false to remove it
*/
private boolean entityValueStatement() throws ContainedException {
+ if(existingValues.contains(subject)) {
+ /* We already have this value, so no need to import it again
+ * Since values are IDed by content, we know it is the same
+ */
+ return false;
+ }
switch (predicate) {
case RDF.TYPE:
/*
diff --git
a/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/RdfRepository.java
b/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/RdfRepository.java
index ab85823..dd1b31d 100644
--- a/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/RdfRepository.java
+++ b/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/RdfRepository.java
@@ -11,6 +11,7 @@
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
+import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
@@ -59,17 +60,86 @@
.build();
private final URI uri;
private final WikibaseUris uris;
+ // SPARQL queries
private final String syncBody;
+ private final String getValues;
+ private final String getRefs;
+ private final String cleanUnused;
+
+ protected String loadSparql(String filename) {
+ URL bodyUrl = getResource(RdfRepository.class, filename);
+ String body = null;
+ try {
+ body = Resources.toString(bodyUrl, Charsets.UTF_8);
+ } catch (IOException e) {
+ throw new FatalException("Can't load " + bodyUrl);
+ }
+ return body;
+ }
public RdfRepository(URI uri, WikibaseUris uris) {
this.uri = uri;
this.uris = uris;
- URL syncBodyUrl = getResource(RdfRepository.class,
"RdfRepository.sync.sparql");
+ syncBody = loadSparql("RdfRepository.sync.sparql");
+ getRefs = loadSparql("GetRefs.sync.sparql");
+ getValues = loadSparql("GetValues.sync.sparql");
+ cleanUnused = loadSparql("CleanUnused.sync.sparql");
+ }
+
+ /**
+ * Collect results of the query into string set
+ * @param TupleQueryResult result Result object
+ * @param String binding Binding name to collect
+ * @return Collection<String>
+ */
+ private Collection<String> resultToCollection(TupleQueryResult result,
String binding) {
+ Collection<String> values = new HashSet<String>();
try {
- syncBody = Resources.toString(syncBodyUrl, Charsets.UTF_8);
- } catch (IOException e) {
- throw new FatalException("Can't load " + syncBodyUrl);
+ while(result.hasNext()) {
+ Binding value = result.next().getBinding(binding);
+ if (value == null) {
+ continue;
+ }
+ values.add(value.getValue().stringValue());
+ }
+ } catch(QueryEvaluationException e) {
+ return values;
}
+ return values;
+ }
+
+ public Collection<String> getValues(String entityId) {
+ UpdateBuilder b = new UpdateBuilder(getValues);
+ b.bindUri("entity:id", uris.entity() + entityId);
+ b.bind("uris.value", uris.value());
+ b.bind("uris.statement", uris.statement());
+ b.bindUri("prov:wasDerivedFrom", Provenance.WAS_DERIVED_FROM);
+
+ return resultToCollection(query(b.toString()), "s");
+ }
+
+ public Collection<String> getRefs(String entityId) {
+ UpdateBuilder b = new UpdateBuilder(getRefs);
+ b.bindUri("entity:id", uris.entity() + entityId);
+ b.bind("uris.statement", uris.statement());
+ b.bindUri("prov:wasDerivedFrom", Provenance.WAS_DERIVED_FROM);
+
+ return resultToCollection(query(b.toString()), "s");
+ }
+
+ /**
+ * Clean subjects if they are not used anymore
+ * @param valueList
+ */
+ public void cleanUnused(Collection<String> valueList) {
+ if(valueList.isEmpty()) {
+ return;
+ }
+ long start = System.currentTimeMillis();
+ UpdateBuilder b = new UpdateBuilder(cleanUnused);
+ b.bindUris("values", valueList);
+ int modified = execute("update", UPDATE_COUNT_RESPONSE, b.toString());
+ log.debug("Cleanup {} millis and modified {} statements",
System.currentTimeMillis() - start, modified);
}
/**
diff --git
a/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/RdfRepository.sync.sparql
b/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/RdfRepository.sync.sparql
index c30cb0b..a94d8c6 100644
---
a/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/RdfRepository.sync.sparql
+++
b/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/RdfRepository.sync.sparql
@@ -13,73 +13,7 @@
}
}
};
-# Clear statements on expanded values in referenes that are no longer used
-DELETE {
- ?s ?p ?o .
-}
-WHERE {
- %entity:id% ?statementPred ?statement .
- FILTER( STRSTARTS(STR(?statement), "%uris.statement%") ) .
- ?statement %prov:wasDerivedFrom% ?ref .
- # Since references are shared we can only clear the values on them when they
are no longer used
- # anywhere else.
- FILTER NOT EXISTS {
- ?otherStatement %prov:wasDerivedFrom% ?ref .
- ?otherEntity ?otherStatementPred ?otherStatement .
- FILTER ( %entity:id% != ?otherEntity ) .
- }
- ?ref ?expandedValuePred ?s .
- # Without this filter we'd try to delete stuff from entities. For example
that pattern above matches
- # ref:_ v:P143 entity:Q328
- # so we'd try to clear everything from Q328 (enwiki). So we filter where ?s
is in the value prefix.
- FILTER( STRSTARTS(STR(?s), "%uris.value%") ) .
- ?s ?p ?o .
- FILTER NOT EXISTS {
- VALUES ( ?s ?p ?o ) {
- %valueStatements%
- }
- }
-};
-# Clear statements about references that are no longer used
-DELETE {
- ?s ?p ?o .
-}
-WHERE {
- %entity:id% ?statementPred ?statement .
- FILTER( STRSTARTS(STR(?statement), "%uris.statement%") ) .
- ?statement %prov:wasDerivedFrom% ?s .
- # Since references are shared we can only clear the values on them when they
are no longer used
- # anywhere else.
- FILTER NOT EXISTS {
- ?otherStatement %prov:wasDerivedFrom% ?s .
- ?otherEntity ?otherStatementPred ?otherStatement .
- FILTER ( %entity:id% != ?otherEntity ) .
- }
- ?s ?p ?o .
- FILTER NOT EXISTS {
- VALUES ( ?s ?p ?o ) {
- %valueStatements%
- }
- }
-};
-# Clear out of date expanded values on statements about the entity
-DELETE {
- ?s ?p ?o .
-}
-WHERE {
- %entity:id% ?statementPred ?statement .
- FILTER( STRSTARTS(STR(?statement), "%uris.statement%") ) .
- ?statement ?expandedValuePred ?s .
- # Without this filter we'd clear all kinds of things. Only try and clear
value nodes.
- FILTER( STRSTARTS(STR(?s), "%uris.value%") ) .
- ?s ?p ?o .
- FILTER NOT EXISTS {
- VALUES ( ?s ?p ?o ) {
- %valueStatements%
- }
- }
-};
-# Clear out of date statements about statements
+# Clear out of date statements about statements
DELETE {
?s ?p ?o .
}
@@ -107,6 +41,5 @@
};
INSERT {
%insertStatements%
-}
-WHERE {};
+} WHERE {}
diff --git
a/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/UpdateBuilder.java
b/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/UpdateBuilder.java
index 345c211..a52e639 100644
--- a/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/UpdateBuilder.java
+++ b/tools/src/main/java/org/wikidata/query/rdf/tool/rdf/UpdateBuilder.java
@@ -49,6 +49,16 @@
return this;
}
+ public UpdateBuilder bindUris(String from, Collection<String> uris) {
+ StringBuilder b = new StringBuilder(uris.size() * 80);
+
+ for (String s : uris) {
+ b.append('<').append(s).append("> ");
+ }
+ bind(from, b.toString().trim());
+ return this;
+ }
+
@Override
public String toString() {
return template;
--
To view, visit https://gerrit.wikimedia.org/r/204225
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I0397dc10fb7fbaf0d11433c31728ed8e28f58d84
Gerrit-PatchSet: 1
Gerrit-Project: wikidata/query/rdf
Gerrit-Branch: master
Gerrit-Owner: Smalyshev <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits