jenkins-bot has submitted this change and it was merged.

Change subject: add console-based loading
......................................................................


add console-based loading

Usage:
```
g = TitanFactory.open("config.properties")
loader = tool.DumpLoader.local(g)
loader.latestDumpName("20150126.json.gz").load()
```

Change-Id: I7137acd378e628940991821a051524d25c72de86
---
M runit.groovy
M runit.sh
M src/main/groovy/org/wikidata/gremlin/Schema.groovy
M src/main/groovy/org/wikidata/gremlin/tool/DumpLoader.groovy
M src/main/java/org/wikidata/gremlin/LoadingTraversal.java
5 files changed, 133 insertions(+), 33 deletions(-)

Approvals:
  Manybubbles: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/runit.groovy b/runit.groovy
index 4539638..bc04503 100644
--- a/runit.groovy
+++ b/runit.groovy
@@ -13,10 +13,4 @@
  * limitations under the License.
  */
 g = TitanFactory.open("config.properties")
-groovy.grape.Grape.grab(group:'org.wikidata', module:'gremlin', 
version:'0.0.9-SNAPSHOT')
-import org.wikidata.gremlin.*;
-w = org.wikidata.gremlin.ConsoleInit.init(this)
-propLoader = new org.wikidata.gremlin.DataLoader(g, true).failOnError(true)
-dataLoader = new org.wikidata.gremlin.DataLoader(g)
-//batchLoader = new org.wikidata.gremlin.DataLoader(g, 
true).batch(true).failOnError(true)
-q = new org.wikidata.gremlin.QueryEngine(g)
+loader = tool.DumpLoader.local(g)
diff --git a/runit.sh b/runit.sh
index 23a2320..63a0326 100644
--- a/runit.sh
+++ b/runit.sh
@@ -13,6 +13,4 @@
 # limitations under the License.
 #
 
-export INSTANCE=$1
-rm ~/.groovy/grapes/org.wikidata/gremlin/jars/gremlin-*-SNAPSHOT.jar
 sh bin/gremlin.sh -l INFO runit.groovy 
diff --git a/src/main/groovy/org/wikidata/gremlin/Schema.groovy 
b/src/main/groovy/org/wikidata/gremlin/Schema.groovy
index e552158..f42fca2 100644
--- a/src/main/groovy/org/wikidata/gremlin/Schema.groovy
+++ b/src/main/groovy/org/wikidata/gremlin/Schema.groovy
@@ -52,7 +52,6 @@
     def lref = addVertexLabel(mgmt, 'reference') // Reference node
     // properties
     def wikibaseId = addProperty(mgmt, 'wikibaseId', String.class)
-    def vid = addProperty(mgmt, 'vid', String.class)
     def type = addProperty(mgmt, 'type', String.class)
     def datatype = addProperty(mgmt, 'datatype', String.class)
     addProperty(mgmt, 'modified', Long.class)
@@ -73,19 +72,18 @@
 
     // Labels
     def claims = addUnidirectedEdgeLabel(mgmt, 'claim', prop, wikibaseId, 
hash, datatype)
-    def refs = addUnidirectedEdgeLabel(mgmt, 'reference', wikibaseId, hash, 
etype, prop)
+    def refs = addEdgeLabel(mgmt, 'reference', wikibaseId, hash, etype)
 
     // Regular indexes
     addIndex(mgmt, 'by_wikibaseId', Vertex.class, [wikibaseId], true)
     addIndex(mgmt, 'by_wikibaseIdE', Edge.class, [wikibaseId])
-    addIndex(mgmt, 'by_vid', Vertex.class, [vid], true)
     addIndex(mgmt, 'by_specialValueNode', Vertex.class, [specialValueNode], 
true)
     addIndex(mgmt, 'by_type', Vertex.class, [type])
     addIndex(mgmt, 'by_etype', Edge.class, [etype])
     addIndex(mgmt, 'by_prop', Edge.class, [prop])
     //addIndex(mgmt, 'by_hash', Vertex.class, [hash]) //? may not be needed
     addIndex(mgmt, 'by_Ehash', Edge.class, [hash])
-    // edges by badges
+    // vertices by badges
     addIndex(mgmt, 'by_badge', Vertex.class, [badge])
 
     // Vertex-centric indexes
diff --git a/src/main/groovy/org/wikidata/gremlin/tool/DumpLoader.groovy 
b/src/main/groovy/org/wikidata/gremlin/tool/DumpLoader.groovy
index baaa853..515090e 100644
--- a/src/main/groovy/org/wikidata/gremlin/tool/DumpLoader.groovy
+++ b/src/main/groovy/org/wikidata/gremlin/tool/DumpLoader.groovy
@@ -16,6 +16,7 @@
 
 import com.tinkerpop.gremlin.driver.Client
 import com.tinkerpop.gremlin.driver.Cluster
+import com.tinkerpop.gremlin.structure.Graph
 import groovy.json.JsonSlurper
 import groovy.util.CliBuilder
 import groovy.util.logging.Slf4j
@@ -79,6 +80,12 @@
     System.exit(0)
   }
 
+  static DumpLoader local(Graph g)
+  {
+    def loader = new DumpLoader()
+    loader.sync(new LocalSync(g).ensureSchema())
+  }
+
   /**
    * Name of the latest dump file.
    */
@@ -116,6 +123,7 @@
 
   def latestDumpName(String latestDumpName) {
     this.latestDumpName = latestDumpName
+    dumpDate = null
     this
   }
 
@@ -141,9 +149,20 @@
 
   def load() {
     if (skipToLine < 0) {
-      loadLanguages()
-      loadSites()
-      loadProperties()
+      if(!sync.getVar('languagesLoaded')) {
+        loadLanguages()
+        sync.setVar('languagesLoaded', true)
+      }
+      if(!sync.getVar('sitesLoaded')) {
+        loadSites()
+        sync.setVar('sitesLoaded', true)
+      }
+      // TODO: this means properties are loaded only once, which
+      // may not work for partial/incremental dumps
+      if(!sync.getVar('propsLoaded')) {
+        loadProperties()
+        sync.setVar('propsLoaded', true)
+      }
     }
     loadItems()
   }
@@ -156,6 +175,7 @@
     // Loading the languages in a big call causes timeouts.  This doesn't.
     def loaded = new 
JsonSlurper().parse(getClass().getResource("/languages.json"), 'UTF-8')
     loaded?.rows.each({sync.language(it[0])})
+
   }
 
   /**
@@ -173,7 +193,7 @@
     log.info "Loading properties"
     eachEntity(latestProperties(), 0, 'load properties',
       {it.startsWith('{')},
-      {line, lineNumber -> sync.entity('load properties', line, lineNumber)})
+      {line, lineNumber -> sync.entity('load properties', line, lineNumber, 
true)})
     sync.sync('load properties', null)
     log.info "Resume now possible with -s <line number>.  `-s 0` will resume 
from this point.  See line number logs for future points."
   }
@@ -184,14 +204,14 @@
   private def loadItems() {
     log.info "Loading items"
     eachEntity(latestDump(), skipToLine, 'load items',
-      {it.startsWith('{') && !it.startsWith('{"id":"P')},
-      {line, lineNumber -> sync.entity('load items', line, lineNumber)})
+      {it.startsWith('{')},
+      {line, lineNumber -> sync.entity('load items', line, lineNumber, false)})
     sync.sync('load items', null)
     log.info "Recording last update time"
     if (dumpDate == null) {
       dumpDate = latestDumpName.substring(0, 8)
     }
-    sync.lastUpdate(FILE_NAME_FORMAT.parseDateTime(dumpDate))
+    sync.setVar('lastUpdate', 
FILE_NAME_FORMAT.parseDateTime(dumpDate).getMillis())
   }
 
   private def latestProperties() {
@@ -248,6 +268,25 @@
   }
 
   /**
+   * Return gzip stream or regular stream depending on file contents
+   * @param src
+   * @return InputStream
+   */
+  private def getMaybeGzipStream(InputStream src) {
+    // check if it's gzip for non-gzip support too
+    def pbs = new PushbackInputStream(src, 2)
+    byte[] gzipSig = new byte[2]
+    pbs.read(gzipSig)
+    pbs.unread(gzipSig)
+    if((gzipSig[0] == (byte) GZIPInputStream.GZIP_MAGIC)
+      && (gzipSig[1] == (byte) (GZIPInputStream.GZIP_MAGIC >> 8))) {
+      new GZIPInputStream(pbs)
+    } else {
+      pbs
+    }
+  }
+
+  /**
    * Opens an input stream that reads the dump as text, unzipping it on the 
fly.
    * If the dump isn't downloaded then it downloads it completely and then
    * reopens it as a stream.
@@ -287,7 +326,8 @@
         latestDumpPart.renameTo(latestDump)
       }
     }
-    new GZIPInputStream(latestDump.newInputStream())
+    // check if it's gzip for non-gzip support too
+    getMaybeGzipStream(latestDump.newInputStream())
   }
 
   void logError(String message, Throwable t) {
@@ -298,9 +338,10 @@
   interface Sync {
     void language(language)
     void site(site)
-    void entity(operationName, entity, lineNumber)
+    void entity(operationName, entity, lineNumber, loadProperties)
     void sync(operationName, lineNumber)
-    void lastUpdate(lastUpdate)
+    def getVar(name)
+    void setVar(name, value)
   }
 
   static class PrintSync implements Sync {
@@ -311,11 +352,12 @@
     void site(site) {
       print "Site ${site}"
     }
-    void entity(operationName, blob, lineNumber) {
+    void entity(operationName, blob, lineNumber, loadProperties) {
       println json.parseText(blob).id
     }
     void sync(operationName, lineNumber) {}
-    void lastUpdate(lastUpdate) {}
+    def getVar(name) { null }
+    void setVar(name, value) {}
   }
 
   static class GremlinSync implements Sync {
@@ -353,14 +395,15 @@
       }
     }
 
-    void entity(operationName, blob, lineNumber) {
+    void entity(operationName, blob, lineNumber, loadProperties) {
       // Sending a big String over Kryo wasn't working so we parse it and send 
it as json
       // which should work better.  Its not as efficient but it works.
       def entity = new JsonSlurper().parseText(blob)
       def task = {loader.retryMostErrors("updating ${entity.id}"){
-        client.submitAsync("g.wt().loadFromEntity(entity); 
g.commitIfSupported()",
-          [entity: entity])
+        client.submitAsync("g.wt().loadFromEntity(entity, props); 
g.commitIfSupported()",
+          [entity: entity, props: loadProperties])
       }}
+
       // The first few items and all properties will have lock contention 
issues if we
       // use too many threads.  So we single thread them.
       if (entity.type != 'item' || lineNumber < 500) {
@@ -384,10 +427,19 @@
       }
     }
 
-    void lastUpdate(lastUpdate) {
-      loader.retryMostErrors('updating last update time'){
-        client.submitAsync("g.variables().set('lastUpdate', lastUpdate)", 
[lastUpdate: lastUpdate.getMillis()])
+    void setVar(name, value) {
+      loader.retryMostErrors("setting variable $name"){
+        client.submitAsync("g.variables().set(name, value)", [name: name, 
value: value])
       }
+
+    }
+
+    def getVar(name) {
+      loader.retryMostErrors("fetching variable $name"){
+        def res = client.submit("g.variables().get(name).orElse(null)", [name: 
name]).all().get()
+        res[0].getObject()
+      }
+      null
     }
 
     void close() {
@@ -396,4 +448,54 @@
       futures.each{it.get()}
     }
   }
+
+  static class LocalSync implements Sync {
+    private def g
+    private def eloader
+    private def ploader
+
+    public LocalSync(Graph g) {
+      this.g = g
+      this.eloader = g.wt().loader()
+      this.ploader = g.wt().buildLoader(true) // property loader
+    }
+
+    LocalSync ensureSchema() {
+      g.wt().ensureSchema()
+      this
+    }
+
+    void language(language) {
+      eloader.initLanguage(language)
+      this
+    }
+
+    void site(site) {
+      eloader.initSite(site)
+    }
+
+    void entity(operationName, blob, lineNumber, loadProperties) {
+      def entity = new JsonSlurper().parseText(blob)
+      if(loadProperties) {
+        ploader.loadFromItem(entity)
+      } else {
+        eloader.loadFromItem(entity)
+      }
+      g.commitIfSupported()
+    }
+
+    void sync(operationName, lineNumber) {}
+
+    def getVar(name) {
+      g.variables().get(name).orElse(null)
+    }
+
+    void setVar(name, value) {
+      g.variables().set(name, value)
+      g.commitIfSupported()
+    }
+
+    void close() {}
+  }
+
 }
diff --git a/src/main/java/org/wikidata/gremlin/LoadingTraversal.java 
b/src/main/java/org/wikidata/gremlin/LoadingTraversal.java
index fd25dd5..4e64d66 100644
--- a/src/main/java/org/wikidata/gremlin/LoadingTraversal.java
+++ b/src/main/java/org/wikidata/gremlin/LoadingTraversal.java
@@ -70,8 +70,8 @@
   /**
    * Load from a pre-fetched object.
    */
-  default Self loadFromEntity(Object item) {
-    return cast(asAdmin().addStep(new StartStep<>(this, 
loader().loadFromItem(item))));
+  default Self loadFromEntity(Object item, boolean loadProperties) {
+    return cast(asAdmin().addStep(new StartStep<>(this, 
buildLoader(loadProperties).loadFromItem(item))));
   }
 
   /**
@@ -89,4 +89,12 @@
     
loader.setEntitySource(graph().variables().<String>get("source").orElse(Loader.WIKIDATA_URL));
     return loader;
   }
+  /**
+   * Build the loader.
+   */
+  default Loader buildLoader(boolean loadProperties) {
+    Loader loader = new Loader(graph(), loadProperties);
+    
loader.setEntitySource(graph().variables().<String>get("source").orElse(Loader.WIKIDATA_URL));
+    return loader;
+  }
 }

-- 
To view, visit https://gerrit.wikimedia.org/r/188117
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I7137acd378e628940991821a051524d25c72de86
Gerrit-PatchSet: 4
Gerrit-Project: wikidata/gremlin
Gerrit-Branch: master
Gerrit-Owner: Smalyshev <[email protected]>
Gerrit-Reviewer: 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

Reply via email to