Manybubbles has uploaded a new change for review.
https://gerrit.wikimedia.org/r/203154
Change subject: WIP: Simplify statement construction
......................................................................
WIP: Simplify statement construction
Change-Id: If2fc2ba2437592322c76a5655d3c4d1f6987fe0e
---
A tools/src/test/java/org/wikidata/query/rdf/tool/ExpandedStatementBuilder.java
M tools/src/test/java/org/wikidata/query/rdf/tool/MungeIntegrationTest.java
M tools/src/test/java/org/wikidata/query/rdf/tool/StatementHelper.java
M tools/src/test/java/org/wikidata/query/rdf/tool/rdf/MungerUnitTest.java
4 files changed, 415 insertions(+), 113 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/wikidata/query/rdf
refs/changes/54/203154/1
diff --git
a/tools/src/test/java/org/wikidata/query/rdf/tool/ExpandedStatementBuilder.java
b/tools/src/test/java/org/wikidata/query/rdf/tool/ExpandedStatementBuilder.java
new file mode 100644
index 0000000..3f85887
--- /dev/null
+++
b/tools/src/test/java/org/wikidata/query/rdf/tool/ExpandedStatementBuilder.java
@@ -0,0 +1,365 @@
+package org.wikidata.query.rdf.tool;
+
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.equalTo;
+import static org.wikidata.query.rdf.tool.StatementHelper.statement;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+
+import org.hamcrest.Matcher;
+import org.openrdf.model.Statement;
+import org.openrdf.model.Value;
+import org.openrdf.model.impl.LiteralImpl;
+import org.wikidata.query.rdf.common.uri.Ontology;
+import org.wikidata.query.rdf.common.uri.Provenance;
+import org.wikidata.query.rdf.common.uri.RDF;
+import org.wikidata.query.rdf.common.uri.SchemaDotOrg;
+import org.wikidata.query.rdf.common.uri.WikibaseUris;
+
+import com.carrotsearch.randomizedtesting.RandomizedTest;
+
+/**
+ * Builds expanded statements in the style of Wikibase's dump flavored export
or
+ * post-munged. Because this is able to build both styles this amounts to the
+ * best way to test the munger on expanded statements. Its therefore super
+ * important that it faithfully reflects what we expect of the munger.
+ */
+public class ExpandedStatementBuilder {
+ private final List<ExtraInfo> extraInfo = new ArrayList<>();
+ private final Random random;
+ private final WikibaseUris uris;
+ private final String entity;
+ private final String property;
+ private final Object value;
+
+ private boolean includeBasicEntity = true;
+ /**
+ * Version set if includeBasicEntity is true.
+ */
+ private Value version;
+ /**
+ * Date modified set if includeBasicEntity is true.
+ */
+ private Value dateModified;
+ private ExpandedValueInfo expandedValue;
+
+ private String statementUri;
+ private String rank = Ontology.NORMAL_RANK;
+ private boolean bestRank = false;
+
+ /**
+ * Null until its built and then can't be changed.
+ */
+ private List<Statement> statements;
+
+ /*
+ * These are built as part of the build step and used later when
+ * transforming from wikibase style to munged style.
+ */
+ private Statement entityDataAboutDecl;
+ private Statement entityDataVersionDecl;
+ private Statement entityDataDateModifiedDecl;
+ private Statement statementTypeDecl;
+
+ public ExpandedStatementBuilder(Random random, WikibaseUris uris, String
entity, String property, Object value) {
+ this.random = random;
+ this.uris = uris;
+ this.entity = entity;
+ this.property = property;
+ this.value = value;
+ }
+
+ /**
+ * Get the entity of this expanded statement.
+ */
+ public String entity() {
+ return entity;
+ }
+
+ /**
+ * Get the value of this expanded statement.
+ */
+ public Object value() {
+ return value;
+ }
+
+ /**
+ * Should this statement be of best rank?
+ */
+ public ExpandedStatementBuilder bestRank(boolean bestRank) {
+ checkCanChange();
+ this.bestRank = bestRank;
+ return this;
+ }
+
+ /**
+ * Add a reference to this statement.
+ */
+ public ExpandedStatementBuilder reference(String property, Object value) {
+ extraInfo.add(new ReferenceInfo(property, value));
+ return this;
+ }
+
+ /**
+ * Add a qualifier to this statement.
+ */
+ public ExpandedStatementBuilder qualifier(String property, Object value) {
+ extraInfo.add(new QualifierInfo(property, value));
+ return this;
+ }
+
+ /**
+ * Add an expanded value statement to this statement.
+ */
+ public ExpandedStatementBuilder expandedValue(String property, Object
value) {
+ if (expandedValue == null) {
+ expandedValue = new ExpandedValueInfo(this.property, null);
+ extraInfo.add(expandedValue);
+ }
+ expandedValue.entries.add(new ExpandedValueInfoEntry(property, value));
+ return this;
+ }
+
+ /**
+ * Get the results in wikibase style.
+ */
+ public List<Statement> wikibaseStyle() {
+ return built();
+ }
+
+ /**
+ * Get the results in wikibase style but shuffled.
+ */
+ public List<Statement> wikibaseStyleShuffled() {
+ List<Statement> wikibaseStyle = wikibaseStyle();
+ Collections.shuffle(wikibaseStyle, random);
+ return wikibaseStyle;
+ }
+
+ /**
+ * Get the results in munged style.
+ */
+ public List<Statement> mungedStyle() {
+ List<Statement> st = built();
+ if (includeBasicEntity) {
+ st.remove(entityDataAboutDecl);
+ st.remove(entityDataVersionDecl);
+ st.remove(entityDataDateModifiedDecl);
+ statement(st, uris.entity() + entity, SchemaDotOrg.VERSION,
version);
+ statement(st, uris.entity() + entity, SchemaDotOrg.DATE_MODIFIED,
dateModified);
+ }
+ st.remove(statementTypeDecl);
+ for (ExtraInfo e : extraInfo) {
+ e.munge(st);
+ }
+ return st;
+ }
+
+ public List<Matcher<? super Statement>> mungedStyleMatchers() {
+ List<Matcher<? super Statement>> matchers = new ArrayList<>();
+ for (Statement s : mungedStyle()) {
+ matchers.add(equalTo(s));
+ }
+ return matchers;
+ }
+
+ public Matcher<Iterable<? extends Statement>> mungedStyleMatcher() {
+ return containsInAnyOrder(mungedStyleMatchers());
+ }
+
+ private void checkCanChange() {
+ if (statements != null) {
+ throw new IllegalStateException("Result already built");
+ }
+ }
+
+ private List<Statement> built() {
+ if (statements == null) {
+ build();
+ }
+ return new ArrayList<>(statements);
+ }
+
+ private void build() {
+ statements = new ArrayList<>();
+ buildBasicEntityIfNeeded();
+ buildStatement();
+ buildReferenceIfNeeded();
+ }
+
+ private void buildBasicEntityIfNeeded() {
+ if (!includeBasicEntity) {
+ return;
+ }
+ if (version == null) {
+ version = new LiteralImpl("a revision number I promise");
+ }
+ if (dateModified == null) {
+ dateModified = new LiteralImpl("a date I promise");
+ }
+ String entityDataUri = uris.entityData() + entity;
+ entityDataAboutDecl = statement(statements, entityDataUri,
SchemaDotOrg.ABOUT, entity);
+ entityDataVersionDecl = statement(statements, entityDataUri,
SchemaDotOrg.VERSION, version);
+ entityDataDateModifiedDecl = statement(statements, entityDataUri,
SchemaDotOrg.DATE_MODIFIED, dateModified);
+ }
+
+ private void buildStatement() {
+ if (statementUri == null) {
+ statementUri = uris.statement() + entity + "-" + randomId();
+ }
+
+ statement(statements, uris.entity() + entity, uris.entity() +
property, statementUri);
+ statementTypeDecl = statement(statements, statementUri, RDF.TYPE,
Ontology.STATEMENT);
+ statement(statements, statementUri, uris.value() + property, value);
+ statement(statements, statementUri, Ontology.RANK, rank);
+ if (bestRank) {
+ statement(statements, statementUri, Ontology.RANK,
Ontology.BEST_RANK);
+ }
+ }
+
+ private void buildReferenceIfNeeded() {
+ for (ExtraInfo e : extraInfo) {
+ e.build();
+ }
+ }
+
+ private String randomId() {
+ return RandomizedTest.randomAsciiOfLength(10);
+ }
+
+ private abstract class ExtraInfo {
+ protected final String property;
+ protected final Object value;
+
+ public ExtraInfo(String property, Object value) {
+ this.property = property;
+ this.value = value;
+ }
+
+ /**
+ * Build the statements representing this extra.
+ */
+ public abstract void build();
+
+ /**
+ * Perform whatever munging we expect the munger to perform.
+ */
+ public abstract void munge(List<Statement> statements);
+ }
+
+ private abstract class AbstractComplexExtraInfo extends ExtraInfo {
+ protected String uri;
+ private Statement typeDecl;
+
+ public AbstractComplexExtraInfo(String property, Object value) {
+ super(property, value);
+ }
+
+ @Override
+ public void build() {
+ if (uri == null) {
+ uri = namespace() + entity + "-" + randomId();
+ }
+ statement(statements, statementUri, declarationPredicate(), uri);
+ typeDecl = statement(statements, uri, RDF.TYPE, type());
+ }
+
+ @Override
+ public void munge(List<Statement> statements) {
+ statements.remove(typeDecl);
+ }
+
+ protected abstract String namespace();
+
+ protected abstract String declarationPredicate();
+
+ protected abstract String type();
+ }
+
+ private class ReferenceInfo extends AbstractComplexExtraInfo {
+ public ReferenceInfo(String property, Object value) {
+ super(property, value);
+ }
+
+ @Override
+ public void build() {
+ super.build();
+ statement(statements, uri, uris.value() + property, value);
+ }
+
+ @Override
+ protected String namespace() {
+ return uris.reference();
+ }
+
+ @Override
+ protected String declarationPredicate() {
+ return Provenance.WAS_DERIVED_FROM;
+ }
+
+ @Override
+ protected String type() {
+ return Ontology.REFERENCE;
+ }
+ }
+
+ private class QualifierInfo extends ExtraInfo {
+ public QualifierInfo(String property, Object value) {
+ super(property, value);
+ }
+
+ @Override
+ public void build() {
+ statement(statements, statementUri, uris.qualifier() + property,
value);
+ }
+
+ @Override
+ public void munge(List<Statement> statements) {
+ // Intentionally a noop
+ }
+ }
+
+ private class ExpandedValueInfo extends AbstractComplexExtraInfo {
+ private List<ExpandedValueInfoEntry> entries = new ArrayList<>();
+
+ public ExpandedValueInfo(String property, Object value) {
+ super(property, value);
+ }
+
+ @Override
+ public void build() {
+ super.build();
+ for (ExpandedValueInfoEntry e : entries) {
+ statement(statements, uri, e.predicate, e.object);
+ }
+ }
+
+ @Override
+ protected String namespace() {
+ return uris.value();
+ }
+
+ @Override
+ protected String declarationPredicate() {
+ return uris.value() + property + "-value";
+ }
+
+ @Override
+ protected String type() {
+ return Ontology.VALUE;
+ }
+ }
+
+ private static class ExpandedValueInfoEntry {
+ private final String predicate;
+ private final Object object;
+
+ public ExpandedValueInfoEntry(String predicate, Object object) {
+ this.predicate = predicate;
+ this.object = object;
+ }
+ }
+}
diff --git
a/tools/src/test/java/org/wikidata/query/rdf/tool/MungeIntegrationTest.java
b/tools/src/test/java/org/wikidata/query/rdf/tool/MungeIntegrationTest.java
index 4f909b6..54d88a3 100644
--- a/tools/src/test/java/org/wikidata/query/rdf/tool/MungeIntegrationTest.java
+++ b/tools/src/test/java/org/wikidata/query/rdf/tool/MungeIntegrationTest.java
@@ -25,10 +25,10 @@
@Test
public void loadTest() throws IOException {
String source = Resources.getResource(MungeIntegrationTest.class,
"test.ttl").toString();
- Munge.Httpd http = new Munge.Httpd(10999, uris, new
Munger(uris).singleLabelMode("en"), source);
+ Munge.Httpd http = new Munge.Httpd(10998, uris, new
Munger(uris).singleLabelMode("en"), source);
http.start();
try {
- assertEquals(1002,
rdfRepository.loadUrl("http://localhost:10999"));
+ assertEquals(1002,
rdfRepository.loadUrl("http://localhost:10998"));
} finally {
http.stop();
}
diff --git
a/tools/src/test/java/org/wikidata/query/rdf/tool/StatementHelper.java
b/tools/src/test/java/org/wikidata/query/rdf/tool/StatementHelper.java
index 855359d..6225d95 100644
--- a/tools/src/test/java/org/wikidata/query/rdf/tool/StatementHelper.java
+++ b/tools/src/test/java/org/wikidata/query/rdf/tool/StatementHelper.java
@@ -1,10 +1,12 @@
package org.wikidata.query.rdf.tool;
+import java.math.BigInteger;
import java.util.List;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
+import org.openrdf.model.impl.IntegerLiteralImpl;
import org.openrdf.model.impl.LiteralImpl;
import org.openrdf.model.impl.StatementImpl;
import org.openrdf.model.impl.URIImpl;
@@ -19,35 +21,31 @@
*/
public class StatementHelper {
/**
- * Statement constructor taking just URIs as strings.
+ * Statement build helper.
*/
- public static Statement statement(String s, String p, String o) {
- return statement(s, p, uri(o));
+ public static Statement statement(String s, String p, Object o) {
+ Value oValue;
+ if (o instanceof String) {
+ oValue = uri(o.toString());
+ } else if (o instanceof Value) {
+ oValue = (Value) o;
+ } else if (o instanceof Integer) {
+ oValue = new IntegerLiteralImpl(BigInteger.valueOf((int) o));
+ } else if (o instanceof Long) {
+ oValue = new IntegerLiteralImpl(BigInteger.valueOf((long) o));
+ } else {
+ throw new IllegalArgumentException("Illegal object: " + o);
+ }
+ return new StatementImpl(uri(s), uri(p), oValue);
}
/**
- * Statement constructor with a value. Use this one for all values.
+ * Statement build helper.
*/
- public static Statement statement(String s, String p, Value o) {
- return new StatementImpl(uri(s), uri(p), o);
- }
-
- /**
- * Statement constructor taking just URIs as strings and appending the
- * statement to a list.
- */
- public static Statement statement(List<Statement> statements, String s,
String p, String o) {
- return statement(statements, s, p, uri(o));
- }
-
- /**
- * Statement constructor with a value appending the statement to a list.
Use
- * this one for all values.
- */
- public static Statement statement(List<Statement> statements, String s,
String p, Value o) {
- Statement statement = statement(s, p, o);
- statements.add(statement);
- return statement;
+ public static Statement statement(List<Statement> statements, String s,
String p, Object o) {
+ Statement st = statement(s, p, o);
+ statements.add(st);
+ return st;
}
/**
diff --git
a/tools/src/test/java/org/wikidata/query/rdf/tool/rdf/MungerUnitTest.java
b/tools/src/test/java/org/wikidata/query/rdf/tool/rdf/MungerUnitTest.java
index ec83423..88a09ce 100644
--- a/tools/src/test/java/org/wikidata/query/rdf/tool/rdf/MungerUnitTest.java
+++ b/tools/src/test/java/org/wikidata/query/rdf/tool/rdf/MungerUnitTest.java
@@ -27,6 +27,7 @@
import org.wikidata.query.rdf.common.uri.SKOS;
import org.wikidata.query.rdf.common.uri.SchemaDotOrg;
import org.wikidata.query.rdf.common.uri.WikibaseUris;
+import org.wikidata.query.rdf.tool.ExpandedStatementBuilder;
import org.wikidata.query.rdf.tool.exception.ContainedException;
import org.wikidata.query.rdf.tool.rdf.Munger.BadSubjectException;
@@ -118,107 +119,38 @@
@Test
public void basicExpandedStatement() throws ContainedException {
- List<Statement> george = basicEntity("Q23");
- String statementUri = uris.statement() +
"Q23-ce976010-412f-637b-c687-9fd2d52dc140";
- Statement statementTypeDecl = statement(george, statementUri,
RDF.TYPE, Ontology.STATEMENT);
- Statement valueDecl = statement(george, statementUri, uris.value() +
"P509", "Q356405");
- Statement rankDecl = statement(george, statementUri, Ontology.RANK,
Ontology.NORMAL_RANK);
- Statement statementDecl = statement("Q23", "P509", statementUri);
- if (randomBoolean()) {
- george.add(0, statementDecl);
- } else {
- george.add(statementDecl);
- }
- munger.munge("Q23", george);
- assertThat(george, hasItem(statementDecl));
- assertThat(george, not(hasItem(statementTypeDecl)));
- assertThat(george, hasItem(valueDecl));
- assertThat(george, hasItem(rankDecl));
+ ExpandedStatementBuilder b = new ExpandedStatementBuilder(getRandom(),
uris, "Q23", "P509", "Q356405");
+ statementBuilderTestCase(b);
// TODO can we rewrite the valueDecl into something without the
repeated
// property?
}
@Test
public void expandedStatementWithReference() throws ContainedException {
- List<Statement> george = basicEntity("Q23");
- String statementUri = uris.statement() +
"Q23-9D3713FF-7BCC-489F-9386-C7322C0AC284";
- String referenceUri = uris.reference() +
"e36b7373814a0b74caa84a5fc2b1e3297060ab0f";
- Statement statementDecl = statement(george, "Q23", "P19",
statementUri);
- Statement statementTypeDecl = statement(george, statementUri,
RDF.TYPE, Ontology.STATEMENT);
- Statement valueDecl = statement(george, statementUri, uris.value() +
"P19", "Q494413");
- Statement rankDecl = statement(george, statementUri, Ontology.RANK,
Ontology.NORMAL_RANK);
- Statement referenceTypeDecl = statement(george, referenceUri,
RDF.TYPE, Ontology.REFERENCE);
- Statement referenceValueDecl = statement(george, referenceUri,
uris.value() + "P854",
- "http://www.anb.org/articles/02/02-00332.html");
- Statement referenceDecl = statement(statementUri,
Provenance.WAS_DERIVED_FROM, referenceUri);
- if (randomBoolean()) {
- george.add(0, referenceDecl);
- } else {
- george.add(referenceDecl);
- }
- munger.munge("Q23", george);
- assertThat(george, hasItem(statementDecl));
- assertThat(george, not(hasItem(statementTypeDecl)));
- assertThat(george, hasItem(valueDecl));
- assertThat(george, hasItem(rankDecl));
- assertThat(george, hasItem(referenceDecl));
- assertThat(george, not(hasItem(referenceTypeDecl)));
- assertThat(george, hasItem(referenceValueDecl));
+ ExpandedStatementBuilder b = new ExpandedStatementBuilder(getRandom(),
uris, "Q23", "P509", "Q356405");
+ b.reference("P854", "http://www.anb.org/articles/02/02-00332.html");
+ statementBuilderTestCase(b);
}
@Test
public void expandedStatementWithQualifier() throws ContainedException {
- List<Statement> george = basicEntity("Q23");
- String statementUri = uris.statement() +
"q23-8A2F4718-6159-4E58-A8F9-6F24F5EFEC42";
- Statement statementDecl = statement(george, "Q23", "P26",
statementUri);
- Statement statementTypeDecl = statement(george, statementUri,
RDF.TYPE, Ontology.STATEMENT);
- Statement valueDecl = statement(george, statementUri, uris.value() +
"P26", "Q191789");
- Statement rankDecl = statement(george, statementUri, Ontology.RANK,
Ontology.NORMAL_RANK);
- Statement qualifierDecl = statement(george, statementUri,
uris.qualifier() + "P580",
- new LiteralImpl("1759-01-06T00:00:00Z", XMLSchema.DATETIME));
- munger.munge("Q23", george);
- assertThat(george, hasItem(statementDecl));
- assertThat(george, not(hasItem(statementTypeDecl)));
- assertThat(george, hasItem(valueDecl));
- assertThat(george, hasItem(rankDecl));
- assertThat(george, hasItem(qualifierDecl));
+ ExpandedStatementBuilder b = new ExpandedStatementBuilder(getRandom(),
uris, "Q23", "P26", "Q191789");
+ b.qualifier("P580", new LiteralImpl("1759-01-06T00:00:00Z",
XMLSchema.DATETIME));
+ statementBuilderTestCase(b);
}
@Test
public void basicExpandedValue() {
- List<Statement> universe = basicEntity("Q1");
- String statementUri = uris.statement() + "q1-someuuid";
- String valueUri = uris.value() + "someotheruuid";
- Statement statementDecl = statement(universe, "Q1", "P580",
statementUri);
- Statement statementTypeDecl = statement(universe, statementUri,
RDF.TYPE, Ontology.STATEMENT);
- Statement valueDecl = statement(universe, statementUri, uris.value() +
"P580",
- new LiteralImpl("-13798000000-01-01T00:00:00Z",
XMLSchema.DATETIME));
- Statement expandedValueDecl = statement(universe, statementUri,
uris.value() + "P580"
- + "-value", valueUri);
- Statement expandedValueTypeDecl = statement(universe, valueUri,
RDF.TYPE, Ontology.VALUE);
- /*
- * Currently wikibase exports the deep time values as strings, not
- * dateTime.
- */
- Statement expandedValueValueDecl = statement(universe, valueUri,
Ontology.Time.VALUE,
- "-13798000000-01-01T00:00:00Z");
- Statement expandedValuePrecisionDecl = statement(universe, valueUri,
Ontology.Time.PRECISION,
- new IntegerLiteralImpl(BigInteger.valueOf(3)));
- Statement expandedValueTimezoneDecl = statement(universe, valueUri,
Ontology.Time.TIMEZONE,
- new IntegerLiteralImpl(BigInteger.valueOf(0)));
- Statement expandedValueCalendarModelDecl = statement(universe,
valueUri, Ontology.Time.CALENDAR_MODEL,
- "Q1985727");
- munger.munge("Q1", universe);
- assertThat(universe, hasItem(statementDecl));
- assertThat(universe, not(hasItem(statementTypeDecl)));
- assertThat(universe, hasItem(valueDecl));
- assertThat(universe, hasItem(expandedValueDecl));
- assertThat(universe, not(hasItem(expandedValueTypeDecl)));
- assertThat(universe, hasItem(expandedValueDecl));
- assertThat(universe, hasItem(expandedValueValueDecl));
- assertThat(universe, hasItem(expandedValuePrecisionDecl));
- assertThat(universe, hasItem(expandedValueTimezoneDecl));
- assertThat(universe, hasItem(expandedValueCalendarModelDecl));
+ ExpandedStatementBuilder b = new ExpandedStatementBuilder(getRandom(),
uris, "Q1", "P580", new LiteralImpl(
+ "-13798000000-01-01T00:00:00Z", XMLSchema.DATETIME));
+ b.expandedValue(Ontology.Time.VALUE, b.value());
+ b.expandedValue(Ontology.Time.PRECISION, 3);
+ b.expandedValue(Ontology.Time.TIMEZONE, 0);
+ b.expandedValue(Ontology.Time.CALENDAR_MODEL, "Q1985727");
+ for (Statement s : b.wikibaseStyle()) {
+ System.err.println(s);
+ }
+ statementBuilderTestCase(b);
}
@Test
@@ -299,6 +231,13 @@
assertThat(universe, hasItem(expandedValueTimezoneDecl));
assertThat(universe, hasItem(expandedValueCalendarModelDecl));
}
+
+ private void statementBuilderTestCase(ExpandedStatementBuilder b) {
+ List<Statement> statements = b.wikibaseStyleShuffled();
+ munger.munge(b.entity(), statements);
+ assertThat(statements, b.mungedStyleMatcher());
+ }
+
// TODO somevalue and novalue
// TODO badges
--
To view, visit https://gerrit.wikimedia.org/r/203154
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: If2fc2ba2437592322c76a5655d3c4d1f6987fe0e
Gerrit-PatchSet: 1
Gerrit-Project: wikidata/query/rdf
Gerrit-Branch: master
Gerrit-Owner: Manybubbles <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits