This is an automated email from the ASF dual-hosted git repository. Cole-Greer pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 82eb611a85e53465d4bb91550cc9d98917c29da4 Merge: 4ea917bd9b 1b288dcac8 Author: Cole Greer <[email protected]> AuthorDate: Thu Jul 2 20:04:06 2026 -0700 Merge branch '3.8-dev' .gitignore | 3 +- bin/process-docs.sh | 316 +++++++-- bin/validate-distribution.sh | 2 +- docs/postprocessor/postprocess.sh | 38 -- docs/postprocessor/processor.awk | 53 -- docs/preprocessor/awk/cleanup.awk | 36 - docs/preprocessor/awk/ignore.awk | 23 - docs/preprocessor/awk/init-code-blocks.awk | 71 -- docs/preprocessor/awk/language-variants.awk | 44 -- docs/preprocessor/awk/prepare.awk | 83 --- docs/preprocessor/awk/progressbar.awk | 36 - docs/preprocessor/awk/tabify.awk | 132 ---- docs/preprocessor/control-characters.sh | 25 - docs/preprocessor/install-plugins.groovy | 44 -- docs/preprocessor/install-plugins.sh | 74 -- docs/preprocessor/preprocess-file.sh | 161 ----- docs/preprocessor/preprocess.sh | 150 ----- docs/preprocessor/uninstall-plugins.sh | 36 - .../dev/developer/development-environment.asciidoc | 135 ++-- docs/src/dev/developer/for-committers.asciidoc | 6 +- docs/src/recipes/olap-spark-yarn.asciidoc | 54 +- docs/src/reference/gremlin-variants.asciidoc | 4 + .../reference/implementations-hadoop-end.asciidoc | 7 +- .../implementations-hadoop-start.asciidoc | 5 +- docs/src/reference/implementations-spark.asciidoc | 3 + docs/src/reference/index.asciidoc | 7 +- docs/src/reference/the-traversal.asciidoc | 6 +- .../language/corpus/DocumentationReader.java | 2 +- pom.xml | 64 ++ tools/tinkerpop-docs/pom.xml | 77 +++ .../gremlin/docs/ConsoleRestartHandler.java | 43 ++ .../tinkerpop/gremlin/docs/GremlinConsole.java | 286 ++++++++ .../gremlin/docs/GremlinDocsExtension.java | 28 +- .../gremlin/docs/GremlinPostprocessor.java | 71 ++ .../gremlin/docs/GremlinTreeprocessor.java | 745 +++++++++++++++++++++ .../docs/PluginDirectoryRestartHandler.java | 130 ++++ .../tinkerpop/gremlin/docs/TabbedHtmlBuilder.java | 291 ++++++++ ...ciidoctor.jruby.extension.spi.ExtensionRegistry | 1 + .../src/main/resources/hadoop-conf/core-site.xml | 33 + .../resources/hadoop-conf/hadoop-docs.properties | 16 +- .../tinkerpop/gremlin/docs/GremlinConsoleTest.java | 320 +++++++++ .../tinkerpop/gremlin/docs/GremlinDocsTest.java | 81 +++ .../gremlin/docs/GremlinPostprocessorTest.java | 103 +++ .../gremlin/docs/GremlinTreeprocessorTest.java | 629 +++++++++++++++++ .../tinkerpop/gremlin/docs/IntegrationTest.java | 131 ++++ .../docs/PluginDirectoryRestartHandlerTest.java | 138 ++++ .../gremlin/docs/TabbedHtmlBuilderTest.java | 286 ++++++++ .../test/resources/integration-fixture.asciidoc | 98 +++ 48 files changed, 3901 insertions(+), 1226 deletions(-) diff --cc docs/src/dev/developer/development-environment.asciidoc index 62b431039f,33fae609df..e0a9559218 --- a/docs/src/dev/developer/development-environment.asciidoc +++ b/docs/src/dev/developer/development-environment.asciidoc @@@ -506,10 -484,10 +459,10 @@@ mvn -Dmaven.javadoc.skip=true --project ** Build AsciiDocs (but don't evaluate code blocks): `bin/process-docs.sh --dryRun` ** Build AsciiDocs (but don't evaluate code blocks in specific files): `bin/process-docs.sh --dryRun docs/src/reference/the-graph.asciidoc,docs/src/tutorial/getting-started,...` ** Build AsciiDocs (but evaluate code blocks only in specific files): `bin/process-docs.sh --fullRun docs/src/reference/the-graph.asciidoc,docs/src/tutorial/getting-started,...` - ** Process a single AsciiDoc file: +pass:[docs/preprocessor/preprocess-file.sh `pwd`/gremlin-console/target/apache-tinkerpop-gremlin-console-*-standalone "" "*" `pwd`/docs/src/xyz.asciidoc]+ + ** Process docs in dry-run mode (no console required): `bin/process-docs.sh --dryRun` * Build JavaDocs/JSDoc: `mvn process-resources -Djavadoc` ** Javadoc to `target/site/apidocs` directory -** JSDoc to the `gremlin-javascript/src/main/javascript/gremlin-javascript/doc/` directory +** JSDoc to the `gremlin-js/gremlin-javascript/doc/` directory * Specify the seed used for `Random` in tests `mvn clean install -DtestSeed` - useful when a test fails, the seed will be printed in the build output so that the test can run with the same version of random (look for "TestHelper" logger in output) * Check for newer dependencies: `mvn versions:display-dependency-updates` or `mvn versions:display-plugin-updates` * Check the effective `pom.xml`: `mvn -pl gremlin-python -Pglv-python help:effective-pom -Doutput=withProfilePom.xml` diff --cc docs/src/recipes/olap-spark-yarn.asciidoc index 31d118f61a,12ea3c77d0..481054233b --- a/docs/src/recipes/olap-spark-yarn.asciidoc +++ b/docs/src/recipes/olap-spark-yarn.asciidoc @@@ -89,29 -89,44 +89,47 @@@ $ hdfs dfs -put data/tinkerpop-modern.k $ . bin/spark-yarn.sh ---- +WARNING: The Hadoop and Spark modules are not included in the 4.0.0-beta.2 distribution. This recipe will +be restored in a future release. + [source,groovy] ---- - hadoop = System.getenv('HADOOP_HOME') - hadoopConfDir = System.getenv('HADOOP_CONF_DIR') - archive = 'spark-gremlin.zip' - archivePath = "/tmp/$archive" - ['bash', '-c', "rm -f $archivePath; cd ext/spark-gremlin/lib && zip $archivePath *.jar"].execute().waitFor() - conf = new Configurations().properties(new File('conf/hadoop/hadoop-gryo.properties')) - conf.setProperty('spark.master', 'yarn') - conf.setProperty('spark.submit.deployMode', 'client') - conf.setProperty('spark.yarn.archive', "$archivePath") - conf.setProperty('spark.yarn.appMasterEnv.CLASSPATH', "./__spark_libs__/*:$hadoopConfDir") - conf.setProperty('spark.executor.extraClassPath', "./__spark_libs__/*:$hadoopConfDir") - conf.setProperty('spark.driver.extraLibraryPath', "$hadoop/lib/native:$hadoop/lib/native/Linux-amd64-64") - conf.setProperty('spark.executor.extraLibraryPath', "$hadoop/lib/native:$hadoop/lib/native/Linux-amd64-64") - conf.setProperty('gremlin.spark.persistContext', 'true') - hdfs.copyFromLocal('data/tinkerpop-modern.kryo', 'tinkerpop-modern.kryo') - graph = GraphFactory.open(conf) - g = traversal().with(graph).withComputer(SparkGraphComputer) - g.V().group().by(values('name')).by(both().count()) + gremlin> hadoop = System.getenv('HADOOP_HOME') + ==>/usr/local/lib/hadoop-3.3.1 + gremlin> hadoopConfDir = System.getenv('HADOOP_CONF_DIR') + ==>/usr/local/lib/hadoop-3.3.1/etc/hadoop + gremlin> archive = 'spark-gremlin.zip' + ==>spark-gremlin.zip + gremlin> archivePath = "/tmp/$archive" + ==>/tmp/spark-gremlin.zip + gremlin> ['bash', '-c', "rm -f $archivePath; cd ext/spark-gremlin/lib && zip $archivePath *.jar"].execute().waitFor() + ==>0 + gremlin> conf = new Configurations().properties(new File('conf/hadoop/hadoop-gryo.properties')) + ==>org.apache.commons.configuration2.PropertiesConfiguration@5b3bb1f7 + gremlin> conf.setProperty('spark.master', 'yarn') + ==>null + gremlin> conf.setProperty('spark.submit.deployMode', 'client') + ==>null + gremlin> conf.setProperty('spark.yarn.archive', "$archivePath") + ==>null + gremlin> conf.setProperty('spark.yarn.appMasterEnv.CLASSPATH', "./__spark_libs__/*:$hadoopConfDir") + ==>null + gremlin> conf.setProperty('spark.executor.extraClassPath', "./__spark_libs__/*:$hadoopConfDir") + ==>null + gremlin> conf.setProperty('spark.driver.extraLibraryPath', "$hadoop/lib/native:$hadoop/lib/native/Linux-amd64-64") + ==>null + gremlin> conf.setProperty('spark.executor.extraLibraryPath', "$hadoop/lib/native:$hadoop/lib/native/Linux-amd64-64") + ==>null + gremlin> conf.setProperty('gremlin.spark.persistContext', 'true') + ==>null + gremlin> hdfs.copyFromLocal('data/tinkerpop-modern.kryo', 'tinkerpop-modern.kryo') + ==>null + gremlin> graph = GraphFactory.open(conf) + ==>hadoopgraph[gryoinputformat->gryooutputformat] + gremlin> g = traversal().withEmbedded(graph).withComputer(SparkGraphComputer) + ==>graphtraversalsource[hadoopgraph[gryoinputformat->gryooutputformat], sparkgraphcomputer] + gremlin> g.V().group().by(values('name')).by(both().count()) + ==>[ripple:1,peter:1,vadas:1,josh:3,lop:3,marko:3] ---- If you run into exceptions, you will have to dig into the logs. You can do this from the command line with diff --cc docs/src/reference/implementations-hadoop-end.asciidoc index 008965b4cc,338792d6fe..57047d3e68 --- a/docs/src/reference/implementations-hadoop-end.asciidoc +++ b/docs/src/reference/implementations-hadoop-end.asciidoc @@@ -16,11 -16,11 +16,14 @@@ KIND, either express or implied. See t specific language governing permissions and limitations under the License. //// + // Continues the Spark/Hadoop OLAP examples (Scala 2.12), so exclude neo4j-gremlin (Scala 2.11) + // to keep it off the console's flat classpath. + [gremlin-docs-plugins-exclude="neo4j-gremlin"] === Input/Output Formats +WARNING: The Hadoop and Spark modules are not included in the 4.0.0-beta.2 distribution. The examples in +this section are presented as static code and will be restored in a future release. + image:adjacency-list.png[width=300,float=right] Hadoop-Gremlin provides various I/O formats -- i.e. Hadoop `InputFormat` and `OutputFormat`. All of the formats make use of an link:http://en.wikipedia.org/wiki/Adjacency_list[adjacency list] representation of the graph where each "row" represents a single vertex, its properties, and its incoming and diff --cc docs/src/reference/implementations-hadoop-start.asciidoc index f20f143388,bcc0c4bfb1..970b8ff462 --- a/docs/src/reference/implementations-hadoop-start.asciidoc +++ b/docs/src/reference/implementations-hadoop-start.asciidoc @@@ -145,13 -148,10 +148,13 @@@ WARNING: OLTP operations on `HadoopGrap for large graphs. In such large graph situations, make use of <<traversalvertexprogram,TraversalVertexProgram>> which is the OLAP Gremlin machine. -[gremlin-groovy] +WARNING: The Hadoop and Spark modules are not included in the 4.0.0-beta.2 distribution. These examples will +be restored in a future release. + +[source,groovy] ---- hdfs.copyFromLocal('data/tinkerpop-modern.kryo', 'tinkerpop-modern.kryo') - hdfs.ls() + hdfs.ls('tinkerpop-modern.kryo') graph = GraphFactory.open('conf/hadoop/hadoop-gryo.properties') g = traversal().with(graph) g.V().count() diff --cc docs/src/reference/index.asciidoc index 104dd7c655,1bd8858574..2465fab0f5 --- a/docs/src/reference/index.asciidoc +++ b/docs/src/reference/index.asciidoc @@@ -41,10 -41,12 +41,11 @@@ include::gremlin-variants.asciidoc[ include::implementations-intro.asciidoc[] include::implementations-tinkergraph.asciidoc[] -include::implementations-neo4j.asciidoc[] - // the hadoop section is split into parts because of serialization issues that are encountered when trying - // to generate graph/spark without restarting the console and currently the only way to force a restart of the - // console is to have a new asciidoc page. + // The hadoop section is split into parts so the Neo4j/Spark plugins (incompatible Scala versions) + // are not active at the same time. Console restarts are now driven by the + // :gremlin-docs-plugins-exclude: attribute on each chapter heading (see implementations-neo4j, + // implementations-hadoop-start, implementations-spark) rather than by page boundaries. include::implementations-hadoop-start.asciidoc[] include::implementations-spark.asciidoc[] include::implementations-hadoop-end.asciidoc[] diff --cc docs/src/reference/the-traversal.asciidoc index 5db65c45db,efaf2d424f..393a458d5a --- a/docs/src/reference/the-traversal.asciidoc +++ b/docs/src/reference/the-traversal.asciidoc @@@ -3042,50 -2847,28 +3042,50 @@@ and pass the value in the params map vi [gremlin-groovy,modern] ---- - g.match("MATCH (p:person {name: $personName})-[:knows]->(f:person)", -traversal = g.V().match( - __.as('a').has(label,'person'), <1> - __.as('a').out('created').as('b'), - __.as('b').in('created').as('c')). - where(__.as('a').out('knows').as('c')). <2> - select('a','c').by('name'); null <3> -traversal.toString() <4> -traversal <5> <6> -traversal.toString() <7> ++g.match('MATCH (p:person {name: $personName})-[:knows]->(f:person)', + ["personName": "marko"]). + select("p", "f").by("name") ---- -<1> Any `has()`-step traversal patterns that start with the match-key are pulled out of `match()` to enable the graph -system to leverage the filter for index lookups. -<2> A `where()`-step with a traversal containing variable bindings declared in `match()`. -<3> A useful trick to ensure that the traversal is not iterated by Gremlin Console. -<4> The string representation of the traversal prior to its strategies being applied. -<5> The Gremlin Console will automatically iterate anything that is an iterator or is iterable. -<6> Both marko and josh are co-developers and marko knows josh. -<7> The string representation of the traversal after the strategies have been applied (and thus, `where()` is folded into `match()`) +The parsed query graph is cached in an LRU cache (up to 1,000 entries), so the same query string is parsed only +once across calls. Edge-case parameter behaviors: + +[width="100%",cols="3,3",options="header"] +|========================================================= +|Situation |Result +|Parameter key present, non-null value |Predicate tests the element property against the supplied value +|Parameter key present, `null` value |Predicate passes only for elements where the property is absent +|Parameter key absent from the map |Predicate always fails — no element matches that filter +|Numeric type mismatch (e.g. `Integer` 29 vs `Long` 29) |Values are compared numerically; `29` (Integer) equals `29L` (Long) +|========================================================= + +When the graph provides an implementation of `Graph.Index` (accessed via `graph.index()`), the executor +automatically uses the index for seed vertex lookup, reducing the initial scan to only those vertices whose +indexed property matches the filter value. This is especially effective when the parameterized query pattern is +constant but the parameter values change across calls — the query graph is cached once and each invocation +performs an index-backed seed lookup rather than a full scan. Whether `Graph.Index` is backed by a real index +structure depends on the graph system; see <<tinkerpop-providers-tinkergql,the provider documentation>> and +your specific graph system's documentation for details. + +===== Unsupported Features + +TinkerGQL is a minimal subset of ISO GQL. The following ISO GQL `MATCH` features are not yet implemented: + +[width="100%",cols="2,4",options="header"] +|========================================================= +|Feature |Notes +|`WHERE` clause |Post-match filtering is not supported inside the `MATCH` string. Use Gremlin's `where()` step after `match()` instead. +|`RETURN` clause |Projection inside the `MATCH` string is not supported. Use `select()` after `match()` to project named variables. +|Inequality / range predicates |Only equality tests (`{key: value}`) are supported. Expressions like `n.age > 30` are not part of the grammar. +|Variable-length paths |Quantified path patterns such as `(a)-[:KNOWS*1..3]->(b)` are not supported. +|Multiple labels per element |`(n:Person:Employee)` — more than one label per node pattern — is not supported. +|`OPTIONAL MATCH` |Optional pattern matching (outer joins) is not supported. +|Aggregation functions |`COUNT`, `SUM`, `AVG`, and similar functions are not part of the grammar. +|OLAP / GraphComputer mode |`match(String)` does not execute in OLAP (GraphComputer) mode. `GqlDeclarativeMatchStrategy` detects a graph-computer traversal context and exits without replacing the placeholder step, resulting in an `UnsupportedOperationException` at execution time. +|========================================================= -IMPORTANT: A `where()`-step is a filter and thus, variables within a `where()` clause are not globally bound to the -path of the traverser in `match()`. As such, `where()`-steps in `match()` are used for filtering, not binding. +Equivalent behaviour for `WHERE` and `RETURN` can be expressed using the standard Gremlin step vocabulary +(`where()`, `select()`, `filter()`, `group()`, etc.). *Additional References* @@@ -4198,13 -3980,8 +4198,13 @@@ g.V(1).property(list, ['age': single(36 g.V(1).valueMap() g.V(1).property('friendWeight',outE('knows').values('weight').sum(),'acl','private') <5> g.V(1).properties('friendWeight').valueMap() <6> -g.addV().property(T.label,'person').valueMap().with(WithOptions.tokens) <7> -g.addV().property(null) <8> +g.V(4).property( + __.V(1).project('friendCount', 'createdSoftware'). + by(__.out('knows').count()). + by(__.out('created').values('name'))) <7> +g.V(4).valueMap() +g.addV().property(T.label,'person').valueMap().with(WithOptions.tokens) <8> - g.addV().property(null) <9> ++g.addV().property((Map) null) <9> g.addV().property(set, null) ---- diff --cc tools/tinkerpop-docs/pom.xml index 0000000000,6c95a45e85..def3a70048 mode 000000,100644..100644 --- a/tools/tinkerpop-docs/pom.xml +++ b/tools/tinkerpop-docs/pom.xml @@@ -1,0 -1,77 +1,77 @@@ + <!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + <project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>tinkerpop</artifactId> - <version>3.8.2-SNAPSHOT</version> ++ <version>4.0.0-SNAPSHOT</version> + <relativePath>../../pom.xml</relativePath> + </parent> + <artifactId>tinkerpop-docs</artifactId> + <name>Apache TinkerPop :: Docs Extension</name> + <description>AsciidoctorJ extension for processing gremlin code blocks in TinkerPop documentation</description> + <packaging>jar</packaging> + + <properties> + <asciidoctorj.version>2.5.13</asciidoctorj.version> + </properties> + + <dependencies> + <dependency> + <groupId>org.asciidoctor</groupId> + <artifactId>asciidoctorj</artifactId> + <version>${asciidoctorj.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>${junit.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest</artifactId> + <version>${hamcrest.version}</version> + <scope>test</scope> + </dependency> + + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.14.0</version> + <configuration> + <!-- AsciidoctorJ 2.5.x requires Java 11+ --> + <release>11</release> + </configuration> + </plugin> + <plugin> + <artifactId>maven-deploy-plugin</artifactId> + <configuration> + <skip>true</skip> + </configuration> + </plugin> + </plugins> + </build> + </project>
