[GitHub] tinkerpop issue #499: TINKERPOP-1520: Difference between 'has' step generate...
Github user spmallette commented on the issue: https://github.com/apache/tinkerpop/pull/499 I added the logging of the seed for that test that uses `Random`: 73859cce8563c3951e39fef58b189acb9718e5c3 It's made for one time use right now - we probably could generalize that a bit for re-use in other tests that use `Random` (and it doesn't make sense to wholly factor out the `Random`). VOTE +1 --- If your project is set up for it, you can reply to this email and have your reply appear on GitHub as well. If your project does not have this feature enabled and wishes so, or if the feature is enabled but not working, please contact infrastructure at infrastruct...@apache.org or file a JIRA ticket with INFRA. ---
[jira] [Commented] (TINKERPOP-1520) Difference between 'has' step generated graphson2.0 in java and python glv implementation
[ https://issues.apache.org/jira/browse/TINKERPOP-1520?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15693051#comment-15693051 ] ASF GitHub Bot commented on TINKERPOP-1520: --- Github user spmallette commented on the issue: https://github.com/apache/tinkerpop/pull/499 I added the logging of the seed for that test that uses `Random`: 73859cce8563c3951e39fef58b189acb9718e5c3 It's made for one time use right now - we probably could generalize that a bit for re-use in other tests that use `Random` (and it doesn't make sense to wholly factor out the `Random`). VOTE +1 > Difference between 'has' step generated graphson2.0 in java and python glv > implementation > - > > Key: TINKERPOP-1520 > URL: https://issues.apache.org/jira/browse/TINKERPOP-1520 > Project: TinkerPop > Issue Type: Bug > Components: language-variant >Affects Versions: 3.2.3 >Reporter: Andy Tolbert > > Noticed that between the java and python implementations, the graphson2.0 > payload generated for a {{has}} step is different. i.e. for the given > traversal: > {{g.E().has("weight", 0.2)}} > The java implementation produces the following graphson: > {code:javascript} > {"@type":"g:Bytecode","@value":{"step":[["E"],["has","weight",{"@type":"g:P","@value":{"predicate":"eq","value":{"@type":"g:Double","@value":0.2}}}]]}} > {code} > where the python implementation produces the following: > {code:javascript} > {"@type":"g:Bytecode","@value":{"step":[["E"],["has","weight",0.2]]}} > {code} > In the java case, a {{g\:P}} typed (predicate) value is provided, where in > the python case that isn't the case. > I'm assuming the java one is correct (primarily since the graph backend seems > to like it and return the expected result). Should GLV implementations > behave this way? I noticed that {{GraphTraversal#has(String propertyKey, > Object value)}} in the java TinkerPop api wraps the value in a predicate > ({{P.eq}}) under the covers > ([link|https://github.com/apache/tinkerpop/blob/master/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java#L922]) > so maybe implementors will need to do the same ([python > link|https://github.com/apache/tinkerpop/blob/master/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py#L193])? -- This message was sent by Atlassian JIRA (v6.3.4#6332)
[GitHub] tinkerpop pull request #499: TINKERPOP-1520: Difference between 'has' step g...
Github user asfgit closed the pull request at: https://github.com/apache/tinkerpop/pull/499 --- If your project is set up for it, you can reply to this email and have your reply appear on GitHub as well. If your project does not have this feature enabled and wishes so, or if the feature is enabled but not working, please contact infrastructure at infrastruct...@apache.org or file a JIRA ticket with INFRA. ---
[jira] [Commented] (TINKERPOP-1520) Difference between 'has' step generated graphson2.0 in java and python glv implementation
[ https://issues.apache.org/jira/browse/TINKERPOP-1520?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15693100#comment-15693100 ] ASF GitHub Bot commented on TINKERPOP-1520: --- Github user asfgit closed the pull request at: https://github.com/apache/tinkerpop/pull/499 > Difference between 'has' step generated graphson2.0 in java and python glv > implementation > - > > Key: TINKERPOP-1520 > URL: https://issues.apache.org/jira/browse/TINKERPOP-1520 > Project: TinkerPop > Issue Type: Bug > Components: language-variant >Affects Versions: 3.2.3 >Reporter: Andy Tolbert > > Noticed that between the java and python implementations, the graphson2.0 > payload generated for a {{has}} step is different. i.e. for the given > traversal: > {{g.E().has("weight", 0.2)}} > The java implementation produces the following graphson: > {code:javascript} > {"@type":"g:Bytecode","@value":{"step":[["E"],["has","weight",{"@type":"g:P","@value":{"predicate":"eq","value":{"@type":"g:Double","@value":0.2}}}]]}} > {code} > where the python implementation produces the following: > {code:javascript} > {"@type":"g:Bytecode","@value":{"step":[["E"],["has","weight",0.2]]}} > {code} > In the java case, a {{g\:P}} typed (predicate) value is provided, where in > the python case that isn't the case. > I'm assuming the java one is correct (primarily since the graph backend seems > to like it and return the expected result). Should GLV implementations > behave this way? I noticed that {{GraphTraversal#has(String propertyKey, > Object value)}} in the java TinkerPop api wraps the value in a predicate > ({{P.eq}}) under the covers > ([link|https://github.com/apache/tinkerpop/blob/master/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java#L922]) > so maybe implementors will need to do the same ([python > link|https://github.com/apache/tinkerpop/blob/master/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py#L193])? -- This message was sent by Atlassian JIRA (v6.3.4#6332)
[jira] [Closed] (TINKERPOP-1520) Difference between 'has' step generated graphson2.0 in java and python glv implementation
[ https://issues.apache.org/jira/browse/TINKERPOP-1520?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Marko A. Rodriguez closed TINKERPOP-1520. - Resolution: Fixed Assignee: Marko A. Rodriguez Fix Version/s: 3.3.0 > Difference between 'has' step generated graphson2.0 in java and python glv > implementation > - > > Key: TINKERPOP-1520 > URL: https://issues.apache.org/jira/browse/TINKERPOP-1520 > Project: TinkerPop > Issue Type: Bug > Components: language-variant >Affects Versions: 3.2.3 >Reporter: Andy Tolbert >Assignee: Marko A. Rodriguez > Fix For: 3.3.0 > > > Noticed that between the java and python implementations, the graphson2.0 > payload generated for a {{has}} step is different. i.e. for the given > traversal: > {{g.E().has("weight", 0.2)}} > The java implementation produces the following graphson: > {code:javascript} > {"@type":"g:Bytecode","@value":{"step":[["E"],["has","weight",{"@type":"g:P","@value":{"predicate":"eq","value":{"@type":"g:Double","@value":0.2}}}]]}} > {code} > where the python implementation produces the following: > {code:javascript} > {"@type":"g:Bytecode","@value":{"step":[["E"],["has","weight",0.2]]}} > {code} > In the java case, a {{g\:P}} typed (predicate) value is provided, where in > the python case that isn't the case. > I'm assuming the java one is correct (primarily since the graph backend seems > to like it and return the expected result). Should GLV implementations > behave this way? I noticed that {{GraphTraversal#has(String propertyKey, > Object value)}} in the java TinkerPop api wraps the value in a predicate > ({{P.eq}}) under the covers > ([link|https://github.com/apache/tinkerpop/blob/master/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java#L922]) > so maybe implementors will need to do the same ([python > link|https://github.com/apache/tinkerpop/blob/master/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py#L193])? -- This message was sent by Atlassian JIRA (v6.3.4#6332)
[jira] [Closed] (TINKERPOP-1454) Create Serializers for Graph objects in Gremlin-Python
[ https://issues.apache.org/jira/browse/TINKERPOP-1454?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Marko A. Rodriguez closed TINKERPOP-1454. - Resolution: Fixed Assignee: Marko A. Rodriguez Fix Version/s: 3.3.0 > Create Serializers for Graph objects in Gremlin-Python > -- > > Key: TINKERPOP-1454 > URL: https://issues.apache.org/jira/browse/TINKERPOP-1454 > Project: TinkerPop > Issue Type: Improvement > Components: io, language-variant >Affects Versions: 3.2.2 >Reporter: Marko A. Rodriguez >Assignee: Marko A. Rodriguez > Fix For: 3.3.0 > > > Right now, Gremlin-Python only supports {{VertexDeserializer}}, etc. We > should add {{VertexSerializer}}. Why? So we can send vertex, edge, etc. > objects in a traversal. > {code} > v = g.V().has('name','stephen').next() > g.V(v).out('knows').toList() // currently doesn't work > g.withSideEffect('x',v).V().out('knows').where(neq('x')) // currently doesn't > work > {code} > Note that the serialization simply needs to encode {{id}} only so this can be > really simple to do. -- This message was sent by Atlassian JIRA (v6.3.4#6332)
[jira] [Created] (TINKERPOP-1568) Change strategy application order
Bryn Cooke created TINKERPOP-1568: - Summary: Change strategy application order Key: TINKERPOP-1568 URL: https://issues.apache.org/jira/browse/TINKERPOP-1568 Project: TinkerPop Issue Type: Improvement Components: process Affects Versions: 3.2.3 Reporter: Bryn Cooke Given a traversal with the structure: a(b(),c(d())) Strategies are applied in the order: {noformat} StrategyA on a StrategyB on a StrategyA on b StrategyB on b StrategyA on c StrategyB on c StrategyA on d StrategyB on d {noformat} This prevents strategies from performing global operations across the traversal and all decedents effectively as children will not have been processed by preceding strategies yet. Say you want a strategy that compresses the entire traversal in to a string for sending over the wire, you want this to happen after everything else, but traversals with children will not have had their children processed. Ideally strategy application would be as follows: {noformat} StrategyA on a StrategyA on b StrategyA on c StrategyA on d StrategyB on a StrategyB on b StrategyB on c StrategyB on d {noformat} That way strategy B can check if it is being applied to the root traversal and if it is it knows that A has been applied globally. -- This message was sent by Atlassian JIRA (v6.3.4#6332)
[jira] [Commented] (TINKERPOP-1564) Distributed OLTP Traversals and the Introduction of Partition Concept
[ https://issues.apache.org/jira/browse/TINKERPOP-1564?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15693204#comment-15693204 ] Marko A. Rodriguez commented on TINKERPOP-1564: --- It will work if you send via GremlinServer or not. However, caveat -- GremlinServer will be the default implementation of the message passing system for multi-machine systems. For single machine graph systems, a thread-based message passing system will be provided. > Distributed OLTP Traversals and the Introduction of Partition Concept > - > > Key: TINKERPOP-1564 > URL: https://issues.apache.org/jira/browse/TINKERPOP-1564 > Project: TinkerPop > Issue Type: Improvement > Components: driver, process, server >Affects Versions: 3.2.3 >Reporter: Marko A. Rodriguez > > This proposal unifies OLTP and OLAP into a single framework that removes the > need for OLAP {{GraphComputer}} by introducing distributed, data local > processing to OLTP. In essence, this is a proposal for a step-by-step query > routing framework within {{Traversal}}. This proposal can work across > machines in a cluster, threads on a machine, or in a hierarchical fashion > machines&threads. The example presented will discuss distribution across > machines in a cluster as its the most complicated scenario. > Currently, an OLTP traversal executes at a particular machine (or thread) and > pulls vertex/edge/etc. data to it accordingly in order to solve the > traversal. In OLAP, the traversal is cloned and distributed to all machines > in the cluster and traversals communicate with one another by sending > {{Traversers}} (i.e. messages) between themselves ensuring data local > processing. Given recent advancements in GremlinServer and > {{RemoteTraversal}}, it is possible to add traverser routing to OLTP and > thus, effect the computational paradigm of Gremlin OLAP in Gremlin OLTP with > some added benefits not possible in Gremlin OLAP. > Assume a 4 machine cluster and the following traversal: > {code} > g.V(1).out(‘knows’).has(‘age’,gt(20)).out(‘likes’).values(‘name’) > {code} > Every time there is a "walk" (adjacency), it is possible that the > {{Traverser}} is no longer accessing data local to the current machine. In > order to do data local query routing, every adjacency would feed into a > {{PartitionStep}}. The traversal above would be cloned (via {{Bytecode}} > distribution) across the cluster where "sibling" {{PartitionSteps}} would > have network access to one another using the same protocol of > {{RemoteConnection}} though called {{PartitionConnection}}. Thus, given the 4 > node cluster example, the above traversal would be overlaid as below. Note > that {{partition()}} would not be a new step in the language, but simply > provided here to show where {{PartitionStrategy}} would insert > {{PartitionSteps}} into the traversal. > {code} > g.V(1).out(‘knows’).partition().has(‘age’,gt(20)).out(‘likes’).partition().values(‘name’).partition() >| | >^ > > __.out(‘knows’).partition().has(‘age’,gt(20)).out(‘likes’).partition().values(‘name’).partition() >| | >| > > __.out(‘knows’).partition().has(‘age’,gt(20)).out(‘likes’).partition().values(‘name’).partition() >| | >| > > __.out(‘knows’).partition().has(‘age’,gt(20)).out(‘likes’).partition().values(‘name’).partition() > {code} > The top traversal is called the "master traversal" and the other three > "worker traversals." Note that this is identical to current Gremlin OLAP. > Now, the master traversal would be the traversal that is {{.next()}}'d for > results. So, when the "master traversal" is {{next()}}'d, {{g.V(1)}} will > fetch {{v[1]}} and then its outgoing knows-adjacencies. These adjacent > "reference vertices" would be fed into the first {{remote()}} and a "routing > algorithm" would determine where in the cluster the particular vertex's data > is. Thus, {{partition()}} ({{PartitionStep}}) serves as a router, pushing > {{Traversers}} local to the data. Finally, note that the final > {{PartitionSteps}} can only feed back to the "master traversal" for ultimate > aggregation and return to the user. > TinkerPop currently has all the structures in place to make this possible: > 1. Encapsulation of computational metadata via {{Traverser}}. > 2. The ability to detach {{Traversers}} and migrate/serialize them via > {{Traverser.detach()}} and {{Traverser.attach()}}. > 3. The concept of {{ReferenceElement}} so the traverser only carries > with i
[jira] [Commented] (TINKERPOP-1564) Distributed OLTP Traversals and the Introduction of Partition Concept
[ https://issues.apache.org/jira/browse/TINKERPOP-1564?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15693208#comment-15693208 ] Marko A. Rodriguez commented on TINKERPOP-1564: --- I went through and distilled all the operations that are implicit in {{TraversalVertexProgram}} that "ride atop" the {{GraphComputer}} framework. This forms the API for a message passing system implementation. Apache TinkerPop will provide both a threaded implementation and a GremlinServer implementation of this API. {code} public interface Router { // move an active traverser to its data local partition public void route(Traverser.Admin traverser); // move an inactive traverser back to the master traversal public void halt(Traverser.Admin traverser); } public interface Master extends Router { // send side-effect data to workers public void sideEffect(final String key, final Object value); // when a barrier is complete, unlock it public void unlock(final Barrier barrier); // the computation is complete and shutdown all workers public void stop(); } public interface Worker extends Router { // send worker-partial side-effect data back to master public void sideEffect(final String key, final Object partialValue); // lock at the respective barrier step and send barrier data to master public void lock(final Barrier barrier); // no more traversers in the worker's partition so it should try and shutdown public void voteToStop(); } {code} > Distributed OLTP Traversals and the Introduction of Partition Concept > - > > Key: TINKERPOP-1564 > URL: https://issues.apache.org/jira/browse/TINKERPOP-1564 > Project: TinkerPop > Issue Type: Improvement > Components: driver, process, server >Affects Versions: 3.2.3 >Reporter: Marko A. Rodriguez > > This proposal unifies OLTP and OLAP into a single framework that removes the > need for OLAP {{GraphComputer}} by introducing distributed, data local > processing to OLTP. In essence, this is a proposal for a step-by-step query > routing framework within {{Traversal}}. This proposal can work across > machines in a cluster, threads on a machine, or in a hierarchical fashion > machines&threads. The example presented will discuss distribution across > machines in a cluster as its the most complicated scenario. > Currently, an OLTP traversal executes at a particular machine (or thread) and > pulls vertex/edge/etc. data to it accordingly in order to solve the > traversal. In OLAP, the traversal is cloned and distributed to all machines > in the cluster and traversals communicate with one another by sending > {{Traversers}} (i.e. messages) between themselves ensuring data local > processing. Given recent advancements in GremlinServer and > {{RemoteTraversal}}, it is possible to add traverser routing to OLTP and > thus, effect the computational paradigm of Gremlin OLAP in Gremlin OLTP with > some added benefits not possible in Gremlin OLAP. > Assume a 4 machine cluster and the following traversal: > {code} > g.V(1).out(‘knows’).has(‘age’,gt(20)).out(‘likes’).values(‘name’) > {code} > Every time there is a "walk" (adjacency), it is possible that the > {{Traverser}} is no longer accessing data local to the current machine. In > order to do data local query routing, every adjacency would feed into a > {{PartitionStep}}. The traversal above would be cloned (via {{Bytecode}} > distribution) across the cluster where "sibling" {{PartitionSteps}} would > have network access to one another using the same protocol of > {{RemoteConnection}} though called {{PartitionConnection}}. Thus, given the 4 > node cluster example, the above traversal would be overlaid as below. Note > that {{partition()}} would not be a new step in the language, but simply > provided here to show where {{PartitionStrategy}} would insert > {{PartitionSteps}} into the traversal. > {code} > g.V(1).out(‘knows’).partition().has(‘age’,gt(20)).out(‘likes’).partition().values(‘name’).partition() >| | >^ > > __.out(‘knows’).partition().has(‘age’,gt(20)).out(‘likes’).partition().values(‘name’).partition() >| | >| > > __.out(‘knows’).partition().has(‘age’,gt(20)).out(‘likes’).partition().values(‘name’).partition() >| | >| > > __.out(‘knows’).partition().has(‘age’,gt(20)).out(‘likes’).partition().values(‘name’).partition() > {code} > The top
[jira] [Created] (TINKERPOP-1569) Decompile lambdas in to regular gremlin
Bryn Cooke created TINKERPOP-1569: - Summary: Decompile lambdas in to regular gremlin Key: TINKERPOP-1569 URL: https://issues.apache.org/jira/browse/TINKERPOP-1569 Project: TinkerPop Issue Type: Improvement Components: process Reporter: Bryn Cooke I've been experimenting recently with decompilation and come up with this method for decompiling lambdas: https://github.com/BrynCooke/dice/blob/master/lambda/src/test/java/org/jglue/dice/lambda/TestDecompiler.java Perhaps this could be useful for converting lamdas to regular gremlin? It only works with serializable lambdas BTW. -- This message was sent by Atlassian JIRA (v6.3.4#6332)
[jira] [Updated] (TINKERPOP-1569) Decompile lambdas in to regular gremlin
[ https://issues.apache.org/jira/browse/TINKERPOP-1569?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] stephen mallette updated TINKERPOP-1569: Affects Version/s: 3.2.3 > Decompile lambdas in to regular gremlin > --- > > Key: TINKERPOP-1569 > URL: https://issues.apache.org/jira/browse/TINKERPOP-1569 > Project: TinkerPop > Issue Type: Improvement > Components: process >Affects Versions: 3.2.3 >Reporter: Bryn Cooke > > I've been experimenting recently with decompilation and come up with this > method for decompiling lambdas: > https://github.com/BrynCooke/dice/blob/master/lambda/src/test/java/org/jglue/dice/lambda/TestDecompiler.java > Perhaps this could be useful for converting lamdas to regular gremlin? > It only works with serializable lambdas BTW. -- This message was sent by Atlassian JIRA (v6.3.4#6332)
[jira] [Commented] (TINKERPOP-1564) Distributed OLTP Traversals and the Introduction of Partition Concept
[ https://issues.apache.org/jira/browse/TINKERPOP-1564?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15693765#comment-15693765 ] pieter martin commented on TINKERPOP-1564: -- Regarding distributed transactions, it is a rather difficult thing. What is the idea for the 'T' in distributed 'OLTP'? For Sqlg's back-ends at least, its not possible to run one transaction across multiple threads/rdbms connections. However it might be possible using JTA and XA transaction manager in java. Each thread/connection will get its own XA data source and the transaction manager will handle the transaction boundries via 2 phase commit. All this is somewhat outside TinkerPop though. It also adds a huge complexity that simply never goes away. So for starters I imagine distributed traversals will be read only or simply violate the regular transaction boundaries? I am not thinking here of GremlinServer, rather just running the gremlin traversal natively. > Distributed OLTP Traversals and the Introduction of Partition Concept > - > > Key: TINKERPOP-1564 > URL: https://issues.apache.org/jira/browse/TINKERPOP-1564 > Project: TinkerPop > Issue Type: Improvement > Components: driver, process, server >Affects Versions: 3.2.3 >Reporter: Marko A. Rodriguez > > This proposal unifies OLTP and OLAP into a single framework that removes the > need for OLAP {{GraphComputer}} by introducing distributed, data local > processing to OLTP. In essence, this is a proposal for a step-by-step query > routing framework within {{Traversal}}. This proposal can work across > machines in a cluster, threads on a machine, or in a hierarchical fashion > machines&threads. The example presented will discuss distribution across > machines in a cluster as its the most complicated scenario. > Currently, an OLTP traversal executes at a particular machine (or thread) and > pulls vertex/edge/etc. data to it accordingly in order to solve the > traversal. In OLAP, the traversal is cloned and distributed to all machines > in the cluster and traversals communicate with one another by sending > {{Traversers}} (i.e. messages) between themselves ensuring data local > processing. Given recent advancements in GremlinServer and > {{RemoteTraversal}}, it is possible to add traverser routing to OLTP and > thus, effect the computational paradigm of Gremlin OLAP in Gremlin OLTP with > some added benefits not possible in Gremlin OLAP. > Assume a 4 machine cluster and the following traversal: > {code} > g.V(1).out(‘knows’).has(‘age’,gt(20)).out(‘likes’).values(‘name’) > {code} > Every time there is a "walk" (adjacency), it is possible that the > {{Traverser}} is no longer accessing data local to the current machine. In > order to do data local query routing, every adjacency would feed into a > {{PartitionStep}}. The traversal above would be cloned (via {{Bytecode}} > distribution) across the cluster where "sibling" {{PartitionSteps}} would > have network access to one another using the same protocol of > {{RemoteConnection}} though called {{PartitionConnection}}. Thus, given the 4 > node cluster example, the above traversal would be overlaid as below. Note > that {{partition()}} would not be a new step in the language, but simply > provided here to show where {{PartitionStrategy}} would insert > {{PartitionSteps}} into the traversal. > {code} > g.V(1).out(‘knows’).partition().has(‘age’,gt(20)).out(‘likes’).partition().values(‘name’).partition() >| | >^ > > __.out(‘knows’).partition().has(‘age’,gt(20)).out(‘likes’).partition().values(‘name’).partition() >| | >| > > __.out(‘knows’).partition().has(‘age’,gt(20)).out(‘likes’).partition().values(‘name’).partition() >| | >| > > __.out(‘knows’).partition().has(‘age’,gt(20)).out(‘likes’).partition().values(‘name’).partition() > {code} > The top traversal is called the "master traversal" and the other three > "worker traversals." Note that this is identical to current Gremlin OLAP. > Now, the master traversal would be the traversal that is {{.next()}}'d for > results. So, when the "master traversal" is {{next()}}'d, {{g.V(1)}} will > fetch {{v[1]}} and then its outgoing knows-adjacencies. These adjacent > "reference vertices" would be fed into the first {{remote()}} and a "routing > algorithm" would determine where in the cluster the particular vertex's data > is. Thus, {{partition()}} ({{PartitionStep}}) serves as a router, pushing > {{Traversers}} local to the data. Finally, no