jenkins-bot has submitted this change and it was merged.
Change subject: Simple DSL example
......................................................................
Simple DSL example
DSL is not finished but ready for testing/somewhat useful. It works like:
./console.sh
g = TinkerGraph.open()
g.of(WikidataTraversal.class).ensureSchema().wd('Q1').properties()
g.of(WikidataTraversal.class).wd('Q23').wd('Q91').out('P509').unstub().properties('labelEn')
g.of(WikidataTraversal.class).all().instanceOf('Q5').namesList();
Change-Id: Ie79d93aeae67a060108603dd8e2394a1e7262cc6
---
M src/main/groovy/org/wikidata/gremlin/DomainSpecificLanguage.groovy
M src/main/groovy/org/wikidata/gremlin/GremlinPlugin.groovy
M src/main/groovy/org/wikidata/gremlin/Loader.groovy
M src/main/groovy/org/wikidata/gremlin/Schema.groovy
A src/main/java/org/wikidata/gremlin/DomainSpecificLanguageTraversal.java
A src/main/java/org/wikidata/gremlin/LoadingTraversal.java
A src/main/java/org/wikidata/gremlin/SelfAware.java
A src/main/java/org/wikidata/gremlin/WikidataTraversal.java
8 files changed, 198 insertions(+), 59 deletions(-)
Approvals:
Smalyshev: Looks good to me, approved
jenkins-bot: Verified
diff --git a/src/main/groovy/org/wikidata/gremlin/DomainSpecificLanguage.groovy
b/src/main/groovy/org/wikidata/gremlin/DomainSpecificLanguage.groovy
index 95274b8..869b7a4 100644
--- a/src/main/groovy/org/wikidata/gremlin/DomainSpecificLanguage.groovy
+++ b/src/main/groovy/org/wikidata/gremlin/DomainSpecificLanguage.groovy
@@ -12,42 +12,38 @@
@Slf4j
class DomainSpecificLanguage {
void setup() {
- // Some syntax sugar for setting properties
- Vertex.metaClass.getProperty = { this.property(it).value(); }
- Vertex.metaClass.setProperty = { name, value ->
this.singleProperty(name, value); }
-
- return // for now
log.info "Setting up domain specific language"
- Pipe.metaClass.randomMark = {
- RandomStringUtils.random(10, true, true)
+
+ // Some syntax sugar for setting properties
+ Vertex.metaClass {
+ getProperty = { delegate.property(it).value(); }
+ setProperty = { name, value -> delegate.singleProperty(name, value); }
}
+
// TODO the loader_ name seems silly
Graph.metaClass.loader_ = null
- Gremlin.addStep('loader')
+ //Gremlin.addStep('loader')
Graph.metaClass.loader = { ->
if (delegate.loader_ == null) {
delegate.loader_ = new Loader(delegate)
}
return delegate.loader_
}
- Gremlin.addStep('wd')
- Graph.metaClass.wd = { id ->
- delegate.loader().byId(id)
- return delegate.V('wikibaseId', id)
+ Graph.metaClass.commitIfSupported = { ->
+ if (delegate.features().graph().supportsTransactions()) {
+ delegate.tx().commit()
+ }
+ }
+ //Gremlin.addStep('wd')
+ //Graph.metaClass.wd = { id ->
+ // delegate.loader().byId(id)
+ // return delegate.of(WikidataTraversal.class).V('wikibaseId', id)
+ //}
+ return // for now
+ Pipe.metaClass.randomMark = {
+ RandomStringUtils.random(10, true, true)
}
// This exists in Tinkerpop 3 but not 2.
- Vertex.metaClass.graph = { ->
- // This probably only works in titan
- return delegate.tx().getGraph()
- }
- Gremlin.addStep('refresh')
- Pipe.metaClass.refresh = {
- delegate.sideEffect{it.graph().loader().byVertex(it)}
- }
- Gremlin.addStep('reload')
- Pipe.metaClass.reload = {
- delegate.sideEffect{it.graph().loader().byVertex(it, true)}
- }
Gremlin.addStep('isA')
Pipe.metaClass.isA = { id ->
delegate.has('P31link', CONTAINS, id).hasNext()
@@ -73,18 +69,6 @@
Gremlin.addStep('claimVertices')
Pipe.metaClass.claimVertices = { prop ->
delegate.out(prop)
- }
- // Produces list of entities that are instances of this class
- // E.g. g.listOf('Q5') are humans
- Gremlin.addStep('listOf')
- Pipe.metaClass.listOf = {
- delegate.V('P31link', it)
- }
- // Produces list of instances of the pipeline
- // E.g. g.wd('Q5').instances() are humans
- Gremlin.addStep('instances')
- Pipe.metaClass.instances = {
- delegate.in('P31')
}
// if the list has elements ranked "preferred", take them, otherwise take
all
// this produces list of claims
diff --git a/src/main/groovy/org/wikidata/gremlin/GremlinPlugin.groovy
b/src/main/groovy/org/wikidata/gremlin/GremlinPlugin.groovy
index e69fc1d..37fb1b4 100644
--- a/src/main/groovy/org/wikidata/gremlin/GremlinPlugin.groovy
+++ b/src/main/groovy/org/wikidata/gremlin/GremlinPlugin.groovy
@@ -4,6 +4,7 @@
import com.tinkerpop.gremlin.groovy.plugin.IllegalEnvironmentException
import com.tinkerpop.gremlin.groovy.plugin.PluginAcceptor
import com.tinkerpop.gremlin.groovy.plugin.PluginInitializationException
+import com.tinkerpop.gremlin.structure.Graph
/**
* Sets up Wikidata plugin.
@@ -11,11 +12,12 @@
class GremlinPlugin extends AbstractGremlinPlugin {
@Override
public String getName() {
- return "wikidata";
+ return "wikidata"
}
@Override
public void afterPluginTo(PluginAcceptor pluginAcceptor) throws
IllegalEnvironmentException, PluginInitializationException {
- pluginAcceptor.addImports(["import org.wikidata.gremlin.*"] as Set);
+ pluginAcceptor.addImports(["import org.wikidata.gremlin.*"] as Set)
+ new DomainSpecificLanguage().setup();
}
}
diff --git a/src/main/groovy/org/wikidata/gremlin/Loader.groovy
b/src/main/groovy/org/wikidata/gremlin/Loader.groovy
index 04323e0..04a7a44 100644
--- a/src/main/groovy/org/wikidata/gremlin/Loader.groovy
+++ b/src/main/groovy/org/wikidata/gremlin/Loader.groovy
@@ -27,7 +27,7 @@
*/
@Slf4j
class Loader {
- final Graph g
+ private final Graph g
private boolean batch = false
// private TitanBatchGraph bgraph = null
/**
@@ -40,14 +40,14 @@
Loader(Graph g, skip_props = true) {
this.g = g
- this.skip_props = skip_props
+ this.skip_props = skip_props
}
/**
* Set if this loader is a batch loader
*/
public void setBatch(boolean val = true) {
- batch = val
+ batch = val
throw new RuntimeException("Not supported yet for Titan 0.9")
// if(batch) {
// bgraph = new TitanBatchGraph(g, VertexIDType.STRING, 100000)
@@ -62,37 +62,29 @@
/**
* Load a wikidata item by id if it isn't in the database.
*/
- void byId(id) {
+ def byId(id) {
def v = g.V().has('wikibaseId', id)
- if (!v.hasNext() || v.next().stub) {
- refreshWikidataItem(id)
+ def found = null
+ if (!v.hasNext() || (found = v.next()).stub) {
+ return refreshWikidataItem(id)
}
- }
-
- /**
- * Loads a vertex from wikibase if it is a stub.
- */
- void byVertex(v, refresh = false) {
- if (v.stub || refresh) {
- refreshWikidataItem(v.wikibaseId)
- }
+ return found
}
/**
* Refresh a wikidata item by id.
*/
- private void refreshWikidataItem(id) {
+ def refreshWikidataItem(id) {
def item = fetchEntity(id)
- loadFromItem(item)
- // We do commit here since it's one-off update
- g.tx().commit()
+ return loadFromItem(item)
+ g.commitIfSupported()
}
/**
* Load into the DB from hashmap stricture
* @param item
*/
- public void loadFromItem(item) {
+ public loadFromItem(item) {
def id = item['id']
def isProperty = (id[0] == 'P')
if(isProperty && skip_props) {
@@ -129,6 +121,7 @@
if(isProperty) {
g.tx().commit()
}
+ return g.v(v.id);
// Not committing here to allow DataLoader to group updates
}
diff --git a/src/main/groovy/org/wikidata/gremlin/Schema.groovy
b/src/main/groovy/org/wikidata/gremlin/Schema.groovy
index ddc67db..8ee9ad6 100644
--- a/src/main/groovy/org/wikidata/gremlin/Schema.groovy
+++ b/src/main/groovy/org/wikidata/gremlin/Schema.groovy
@@ -162,6 +162,7 @@
// wikibaseId is needed for Batch loading
g.addVertex(T.label, 'special', 'specialValueNode', 'novalue', 'stub',
false, 'wikibaseId', 'novalue')
}
- g.tx().commit()
+
+ g.commitIfSupported()
}
}
diff --git
a/src/main/java/org/wikidata/gremlin/DomainSpecificLanguageTraversal.java
b/src/main/java/org/wikidata/gremlin/DomainSpecificLanguageTraversal.java
new file mode 100644
index 0000000..dd863ad
--- /dev/null
+++ b/src/main/java/org/wikidata/gremlin/DomainSpecificLanguageTraversal.java
@@ -0,0 +1,49 @@
+package org.wikidata.gremlin;
+
+import com.tinkerpop.gremlin.process.graph.GraphTraversal;
+import com.tinkerpop.gremlin.process.graph.step.sideEffect.IdentityStep;
+import com.tinkerpop.gremlin.process.graph.step.sideEffect.StartStep;
+import com.tinkerpop.gremlin.structure.Vertex;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Implementations of methods to load items from wikidata and ensure the schema
+ * is good.
+ */
+public interface DomainSpecificLanguageTraversal<S, E, Self> extends
GraphTraversal<S, E>, SelfAware<Self> {
+ /**
+ * Seed the graph traversal with all things.
+ */
+ default Self all() {
+ return cast(addStep(new StartStep<>(this, sideEffects().getGraph().V())));
+ }
+
+ /**
+ * Return all items that are an 'instanceof' the current item.
+ */
+ default Self instances() {
+ return cast(in("P31"));
+ }
+
+ /**
+ * Filter the current list to those things that are an 'instanceOf' the
provided id.
+ */
+ default Self instanceOf(String id) {
+ return cast(has("P31link", id));
+ }
+
+ /**
+ * Produce list of id-name pairs for human inspection.
+ */
+ default Self namesList() {
+ return cast(map(t -> {
+ Map<String, String> map = new LinkedHashMap<>();
+ Vertex v = (Vertex) t.get();
+ map.put("id", v.property("wikibaseId").value().toString());
+ map.put("name", v.property("labelEn").orElse("unknown").toString());
+ return map;
+ }));
+ }
+}
diff --git a/src/main/java/org/wikidata/gremlin/LoadingTraversal.java
b/src/main/java/org/wikidata/gremlin/LoadingTraversal.java
new file mode 100644
index 0000000..f29d76b
--- /dev/null
+++ b/src/main/java/org/wikidata/gremlin/LoadingTraversal.java
@@ -0,0 +1,59 @@
+package org.wikidata.gremlin;
+
+import com.tinkerpop.gremlin.process.graph.GraphTraversal;
+import com.tinkerpop.gremlin.process.graph.step.sideEffect.IdentityStep;
+import com.tinkerpop.gremlin.process.graph.step.sideEffect.StartStep;
+import com.tinkerpop.gremlin.structure.Vertex;
+
+/**
+ * Implementations of methods to load items from wikidata and ensure the schema
+ * is good.
+ */
+public interface LoadingTraversal<S, E, Self> extends GraphTraversal<S, E>,
SelfAware<Self> {
+ /**
+ * Ensure schema is setup.
+ */
+ default Self ensureSchema() {
+ Schema schema = new Schema(sideEffects().getGraph());
+ schema.setupSchema();
+ schema.setupConstantData();
+ return cast(addStep(new IdentityStep<>(this)));
+ }
+
+ /**
+ * Load id from wikidata (if it isn't already loaded) and start the
traversal there.
+ */
+ default Self wd(String id) {
+ return cast(addStep(new StartStep<>(this, loader().byId(id))));
+ }
+
+ /**
+ * Forcibly refresh a vertex from wikidata.
+ */
+ default Self refresh() {
+ return cast(sideEffect((t) -> {
+ Vertex v = (Vertex) t.get();
+ System.err.println(v);
+ loader().refreshWikidataItem(v.property("wikibaseId").value());
+ }));
+ }
+
+ /**
+ * Refresh a vertex from wikidata if it is a stub.
+ */
+ default Self unstub() {
+ return cast(sideEffect((t) -> {
+ Vertex v = (Vertex) t.get();
+ if ((Boolean)v.property("stub").value()) {
+ loader().refreshWikidataItem(v.property("wikibaseId").value());
+ }
+ }));
+ }
+
+ /**
+ * Fetch the loader to use for this traversal.
+ */
+ default Loader loader() {
+ return sideEffects().getOrCreate("loader", () -> new
Loader(sideEffects().getGraph()));
+ }
+}
diff --git a/src/main/java/org/wikidata/gremlin/SelfAware.java
b/src/main/java/org/wikidata/gremlin/SelfAware.java
new file mode 100644
index 0000000..fad5284
--- /dev/null
+++ b/src/main/java/org/wikidata/gremlin/SelfAware.java
@@ -0,0 +1,13 @@
+package org.wikidata.gremlin;
+
+import com.tinkerpop.gremlin.process.graph.GraphTraversal;
+import com.tinkerpop.gremlin.process.graph.step.sideEffect.IdentityStep;
+import com.tinkerpop.gremlin.process.graph.step.sideEffect.StartStep;
+import com.tinkerpop.gremlin.structure.Vertex;
+
+/**
+ * Objects of this type can cast things to their ultimate type.
+ */
+public interface SelfAware<Self> {
+ Self cast(Object o);
+}
diff --git a/src/main/java/org/wikidata/gremlin/WikidataTraversal.java
b/src/main/java/org/wikidata/gremlin/WikidataTraversal.java
new file mode 100644
index 0000000..1f79dcf
--- /dev/null
+++ b/src/main/java/org/wikidata/gremlin/WikidataTraversal.java
@@ -0,0 +1,38 @@
+package org.wikidata.gremlin;
+
+import com.tinkerpop.gremlin.process.TraversalStrategies;
+import com.tinkerpop.gremlin.process.graph.GraphTraversal;
+import com.tinkerpop.gremlin.process.graph.strategy.TraverserSourceStrategy;
+import com.tinkerpop.gremlin.process.util.DefaultTraversal;
+import com.tinkerpop.gremlin.process.util.DefaultTraversalStrategies;
+import com.tinkerpop.gremlin.structure.Graph;
+
+/**
+ * Traversal interface defining new steps for wikidata. Note that this must
be written in Java
+ * because Groovy doesn't yet support default method implementations on
interface methods.
+ */
+public interface WikidataTraversal<S, E> extends GraphTraversal<S, E>,
+ LoadingTraversal<S, E, WikidataTraversal<S, E>>,
+ DomainSpecificLanguageTraversal<S, E, WikidataTraversal<S, E>> {
+
+ @Override
+ default WikidataTraversal<S, E> cast(Object self) {
+ return (WikidataTraversal) self;
+ }
+
+ static <S> WikidataTraversal<S, S> of(Graph graph) {
+ return new DefaultWikidataTraversal(graph);
+ }
+
+ class DefaultWikidataTraversal extends DefaultTraversal implements
WikidataTraversal {
+ static {
+ DefaultTraversalStrategies traversalStrategies = new
DefaultTraversalStrategies();
+ traversalStrategies.addStrategy(TraverserSourceStrategy.instance());
+
TraversalStrategies.GlobalCache.registerStrategies(DefaultWikidataTraversal.class,
traversalStrategies);
+ }
+
+ public DefaultWikidataTraversal(Graph graph) {
+ super(graph);
+ }
+ }
+}
--
To view, visit https://gerrit.wikimedia.org/r/183307
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Ie79d93aeae67a060108603dd8e2394a1e7262cc6
Gerrit-PatchSet: 5
Gerrit-Project: wikidata/gremlin
Gerrit-Branch: master
Gerrit-Owner: Manybubbles <[email protected]>
Gerrit-Reviewer: Smalyshev <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits