Filter using edges / vertices - graph

I try to filter nodes :
user = g.v(42);
g.idx('comparisons')[[id:Neo4jTokens.QUERY_HEADER + '*']]
.filter{
if (it.out('COMPARED_VALUE1').in('VOTED').in('VOTES').next().equals(user))
{
return true;
}
return false;
}.count();
I don't really understand how pipes works, but I understand that the next() breaks something in the filter "loop".
I should get 2 results, but I get none.
Regards,

I might need to amend my answer as I could require more specifics on what you are trying to achieve (as #Michael also requested), but if you think your problem is with next(), then consider the following:
user = g.v(42);
g.idx('comparisons')[[id:Neo4jTokens.QUERY_HEADER + '*']]
.filter{it.out('COMPARED_VALUE1').in('VOTED').in('VOTES').next().equals(user)}.count();
First, note above that your filter closure can immediately reduce to that (which will yield the same error, of course). Given that filter closure you are assuming that a user vertex will come out of the pipeline when you next(). That may not be the case. As such, I would re-write the filter closure as:
user = g.v(42);
g.idx('comparisons')[[id:Neo4jTokens.QUERY_HEADER + '*']].filter{
def p = it.out('COMPARED_VALUE1').in('VOTED').in('VOTES')
p.hasNext() ? p.next().equals(user) : false
}.count();
That should likely solve your problem right there given the assumption that you only need to evaluate the first item in the pipeline p which is effectively what you were doing before. I wonder if you couldn't simply use except/retain pattern here to get your answer as it is a bit less convoluted:
user = g.v(42);
g.idx('comparisons')[[id:Neo4jTokens.QUERY_HEADER + '*']]
.out('COMPARED_VALUE1').in('VOTED').in('VOTES').retain([user])
.count();
Hopefully something here puts on you on the right track to your answer.

What do you want to achieve?
Sorry my gremlin knowledge is close to zero these days.
In cypher it would probably look like this
START user=node(42), comp=node:comparisons("id:*")
MATCH comp-[:COMPARED_VALUE1]->()<-[:VOTED*2]-(user)
RETURN count(*)

Related

Gremlin continue traversal only if 2 vertices are not the same

I have a query which looks at 2 different vertices and I want to stop traversing if they don't both roll up to the same root ancestor via a path of "contains" edges.
g.V('node1')
.until(hasLabel('root')).repeat(in('contains')).as('node1Root')
.V('node2')
.until(hasLabel('root')).repeat(in('contains')).as('node2Root')
//FILTER|WHERE clause
I'd like to confirm that node1Root and node2root are the same vertex before continuing the traversal, but for the life of me I cannot figure out how to do this.
I've tried the following:
g.V('node1')
.until(hasLabel('root')).repeat(in('contains')).as('node1Root')
.V('node2')
.until(hasLabel('root')).repeat(in('contains')).as('node2Root')
//.where('node1Root', P.eq('node2Root')
//.where(select("node1Root").is(P.eq("node2Root")))
//.where(select("node1Root").is("node2Root"))
What's interesting is that the following query does work to filter appropriately.
g.V('node1').as('1')
.V('node2').as('2')
.where('1', P.eq('2'))
I'm not sure if there's something up with the until/repeat that screws it up or if I'm just doing something blatantly wrong. Any help would be much appreciated.
Thanks!
I found How to check equality with nodes from an earlier part of query in Gremlin?
and it seems like you use "as" with the same key as the previous "as" and if they match its considered equal.
So here's the winner (I think):
g.V('node1')
.until(hasLabel('root')).repeat(in('contains')).as('node1Root')
.V('node2')
.until(hasLabel('root')).repeat(in('contains')).as('node2Root')
.where(select('node1Root').as('node2Root')
//.not(select('node1Root').as('node2Root')) //OR this to determine they aren't the same
//continue traversal
I also found that my original issue was that the .until().repeat() steps could return a LIST, but in my case I know that my graph model will always return a single 'root' so to make it work, I can use 'unfold'
g.V('node1')
.until(hasLabel('root')).repeat(in('contains')).unfold().as('node1Root')
.V('node2')
.until(hasLabel('root')).repeat(in('contains')).unfold().as('node2Root')
.where('node1Root', P.eq('node2Root')
I think I'll be going with the second solution because I'm much more confident in it, unless I hear otherwise.
You can try this gremlin query
g.V(node1-id)
.map(until(hasLabel('root')).repeat(in().aggregate('x')).cap('x')).as("array")
.V(node2-id)
.until(
as("i").select("array").unfold().as("j")
.where("i", eq("j"))
).repeat(in())
Here we are putting all the vertices in path to root from node1 in an array, and secondly we are checking existence of node in array.
this query can only work with traversal with only one iteration because aggregate step collect to a global variable to traversal that means it will be same array for every iteration. To fix this If you are doing this on jvm do use lamda/groovy closures
g.V(node-start-id-1,node-start-id-2)
.map(
{ x->
var v = x.get()
var g = getGraph().get().traversal();
g.V(v.id())until(hasLabel('root')).repeat(in().aggregate('x')).cap('x')).next()
}
)
.as("array")
.V(node2-id)
.until(
as("i").select("array").unfold().as("j")
.where("i", eq("j"))
).repeat(in())

How do I return to a certain line or argument in a function in R?

I have a function that validates a url based on input from a user. The way the function is set up, if the url doesn't validate (either because it doesn't exist or because it is a duplicate) the function simply ends.
How do I make it so that if the url isn't validated, the user goes back to the input dialogue to start the validation process over again instead of just ending the function?
exfun <- function(){
x <- toupper(readline("Do you want to do the function? Y/N......."))
if (x == "Y"){
writeLines("This is where the function body would be, but it's huge so for the sake of this StackExchange question, we'll just make it a simple thing")
} else
writeLines("Well then why did you start the function? We'll try this again")
#This is where I would like the function to return to the "x<-...." line.
There are a few places where I would like to be able to "return to line X" as there are at least two validation points. I have it set up as a series of if else arguments which else into a message. How can I make it else into a message and bring the user back to the beginning/a previous validation test?
I fiddled with the repeat function, but couldn't get it to return from if else correctly.
I'm not really answering your question, but I'll give you an example that might help you (and probably someone will give a hint to improve this).
You can set a while loop and put conditions to continue the loop or to end it, simply like this:
i <- 1
while (T) {
print(i)
i <- i + 1
if (i==5) {
print("NEXT")
next
}
if (i==10) break
}
As you see, the if with next conditions do something in your code, and keep running it after the command print("NEXT"). Also, the break is inside a condition to stop your loop.
I hope it helps, because with your example is difficult to give a full answer.

xquery "last" function with other selectors

I am curious how to use the last() function in Xquery along with other "selectors" (not sure of the correct lingo). Here is what I have (and this works):
for $lastscoreplay in //bbgame/plays/period[last()]/play[#action="GOOD"]
return <datarow>
<lastscoreplay>{data($lastscoreplay/#uni)}</lastscoreplay>
</datarow>
But, I want to select the last play where the #action equals GOOD. If that makes sense. I would think I could do this but it does not work:
for $lastscoreplay in //bbgame/plays/period[last()]/play[last()][#action="GOOD"]
return <datarow>
<lastscoreplay>{data($lastscoreplay/#uni)}</lastscoreplay>
</datarow>
Sorry I am still rather new to Xquery and coding in general so sorry if this is easy and I just don't see the problem. Thanks for any help!
You query get's the last play, regardless of #action, and then filters that last play by [#action="GOOD"]. Instead, you should first filter by #action, then get the last one:
//bbgame/plays/period[last()]/play[#action="GOOD"][last()]
The full query:
for $lastscoreplay in //bbgame/plays/period[last()]/play[#action="GOOD"][last()]
return
<datarow>
<lastscoreplay>{ data($lastscoreplay/#uni) }</lastscoreplay>
</datarow>
In some cases the accepted answer won't work, if that happens try this alternative:
let $all := /bbgame/plays/period[last()]/play[#action="GOOD"]
return $all[last()]

A seemingly silly way of using the Stream API that leads to the need for Predicate<Boolean>

A predicate on booleans seems a little silly to me (well, at least in the following scenario):
static Set<A> aSet = ...;
checkCondition(B b) {
return aSet.stream()
.map(b::aMethodReturningBoolean)
.filter((Boolean check) -> check)
.limit(1).count() > 0;
}
What I am doing is that given the object b, checking whether there is at least one member of aSet that satisfies a certain condition with respect to b.
Everything is working fine, but the line filter((Boolean check) -> check) is like a tiny little pin pricking me! Is there a way I can avoid it? I mean, if I have a line in my code that is literally the identity function, then there must be something wrong with my approach.
All you need is
return aSet.stream().anyMatch(b::aMethodReturningBoolean);
which is much more readable.

Drools, graph traversal, query to find root nodes

I have a Java-side class with essential behaviour like:
declare Datum
description: String
broader: List <Datum>
narrower: List <Datum>
end
I want to write
query rootDatumsFor(Datum datum)
that provides a list of the root datums - that is, work "up" the broader property and return a list of each datum that has an empty broader list.
I am getting totally confused how to write this - mainly because of the negation involved.
I think I want something like
query rootDatumsFor( Datum datum )
not Datum() from $datum.broader
or
rootDatumsFor( $datum.broader )
end
But I am getting confused on both parts. If there are no broader terms, which the not should detect, how do I "return" the current value of $datum? I feel each part wants a $result and I want to do a $result: $datum but that isn't valid.
And I'm not certain how to do the recursion. Should I have rootDatumsFor(datum, result) and do it via binding?
I've seen examples that do things likes Datum( this == $datum) but that doesn't seem to be accepted when I try it.
Any assistance, whilst I keep re-reading the docn to find a little clue how to proceed, would be much appreciated.
To find all Datum facts with an empty broaderlist, all you have to do is
query rootDatumsFor( Datum $datum )
$datum: Datum( broader.size() == 0 )
end

Resources