How to avoid "Multiple properties exist for the provided key, use Vertex.properties(name)"? - graph

How to avoid "Multiple properties exist for the provided key, use Vertex.properties(name)" when the property has multiple values.
Vertex has a property called name and it has multiple values.
How to get anyone value even though it has multiple values
%%gremlin
g.V('d65135a3-8cd3-4edd-bc8d-f7087557e2a9').
project('s','s1').
by(values('name')).
by(outE('owns').inV().hasLabel('xy').elementMap())
Error:
{
"detailedMessage": "Multiple properties exist for the provided key, use Vertex.properties(name)",
"requestId": "71391776-ad7f-454d-8413-3032a9800211",
"code": "InternalFailureException"
}

I tried reproducing your issue using this sample graph:
g.addV('set-test').
property('mySet','one').
property(set, 'mySet','two').
property(id,'set-test1')
but I was able to return properties OK.
g.V('set-test1').
project('s').
by(values('mySet'))
{'s': 'one'}
and to get every member of the set:
g.V('set-test1').
project('s','s2').
by(values('mySet').fold())
{'s': ['one', 'two'], 's2': ['one', 'two']}
However, I was able to reproduce the message by doing this:
g.V('set-test1').
project('s1','s2').
by(values('mySet'))
{
"detailedMessage": "Multiple properties exist for the provided key, use Vertex.properties(mySet)",
"requestId": "04e43bad-173c-454b-bf3c-5a59a3867ef6",
"code": "InternalFailureException"
}
Please note however, that Neptune is showing the same behavior in this case that you would see from Apache TinkerPop's TinkerGraph, so using fold is probably the way to go here as it will allow the query to complete successfully.
As a side note, "multi property" values (such as sets) do allocate an ID to each set member. However, this is highly implementation dependent, and I would not rely on these IDs. For example, Neptune does not persist property IDs in the database. They are generated "just in time" and can change. For completeness though, here is an example of using property ID values:
g.V('set-test1').properties('mySet').id()
1002125571
1002283485
We can the use those ID values in a query such as:
g.V('set-test1').
project('s1').
by(properties('mySet').hasId('1002283485').value())
{'s1': 'two'}

Related

Gremlin/AWS Neptune: Adding Edge w/ Properties

I currently have a series of two vertices in a parent/child relationship, two edges between them that I have no issue with.
The issue happens when I start attempting to add properties to the edge and I get an error message that gives only some help:
{
"requestId": "...",
"code": "InternalFailureException",
"detailedMessage": "null:to([[SelectOneStep(last,child)]])"
}
I can run the same pattern below on Gremlify, but I understand that is 3.5 as opposed to Neptune on 3.4.
Do I need to point back to the edge itself after adding in all the properties or am I supposed to specify to(select('child')) and then add all the properties while in scope (and then return back to child)?
Traversal Query:
g.V(13695)
.out("latest_parent_to").as("child")
.in("parent_to")
.addE("role")
.property(single,'name','some_role')
.to(
select("child")
).select("child")
Update: I made a few changes to try the other thought: addE > to(select(...)) > set properties. Different error this time:
{
"requestId": "77ee2b5b-8309-4226-b163-8b253450c721",
"code": "UnsupportedOperationException",
"detailedMessage": "Cardinality specification may not be used with Edge properties."
}
The reason for using the single cardinality is every property stored/returned as a set. This was to prevent accidentally appending when one should update.

Advanced filter can't express ISNULL?

These two filters return zero results:
resource.labels:* AND resource.labels.namespace_name:*
resource.labels:* AND NOT resource.labels.namespace_name:*
While this one returns plenty:
resource.labels:*
I have three questions about this:
What's going on here?
More importantly, how do I exclude a particular value of
namespace_name while not excluding records that don't define
namespace_name ?
Similarly, how do I write a filter for all records that don't define namespace_name?
I work on Stackdriver Logging and have worked with the code that handles queries.
You are correct: something's up with the presence operator (:*), and it works differently than the other operators. As a result the behavior of a negated presence operator is not intuitive (or particularly useful).
We consider this a bug, and it's something that I'd really like to fix; however, fixing this class of bug is a lengthy process, so I've proposed some workarounds.
What's going on here?
I cannot reproduce your first "zero result" filter: resource.labels:* AND resource.labels.namespace_name:*
This gives me a large list of logs that contain the namespace_name label. For what it's worth, resource.labels.namespace_name:* implies resource.labels:*, so really you only need the latter half of this filter.
Your second "zero result" filter: resource.labels:* AND NOT resource.labels.namespace_name:*
... runs into a bug where field presence check (:*) does not interact properly with negation.
More importantly, how do I exclude a particular value of namespace_name while not excluding records that don't define namespace_name ?
While not required by the logging API, GCP-emitted resources generally emit the same sets of labels for a given resource type. You can take advantage of this by using resource.type to isolate resources-with-label from resources-without-label, then only apply the label constraint to the resources-with-label clause:
(resource.type != "k8s_container") OR
(resource.type = "k8s_container" AND resource.labels.namespace_name != "my-value")
Here, we are relying on all k8s_container-type entries having the namespace_name label, which should generally be the case. You can modify this to select multiple Kubernetes-prefixed resources:
(NOT resource.type:"k8s_") OR
(resource.type:"k8s_" AND resource.labels.namespace_name != "my-value")
... or use a complex resource.type clause to specifically select which you want to include/exclude from the namespace matching.
(NOT (resource.type = "k8s_container" OR resource.type = "k8s_pod")) OR
((resource.type = "k8s_container" OR resource.type = "k8s_pod") AND resource.labels.namespace_name != "my-value")
You cannot query for a k8s_container type that does not have the namespace_name label, but those should generally not be emitted in the first place.
Similarly, how do I write a filter for all records that don't define namespace_name?
You can't do this right now because of the bug. I think your best bet is to identify all of the resource types that use namespace_name and exclude those types with a resource.type filter:
NOT (
resource.type = "k8s_container" OR
resource.type = "k8s_pod" OR
resource.type = "knative_revision")
Note that, as mentioned earlier, while it's possible (allowed by the API) to have a k8s_container resource without a namespace_name label, emitted k8s_container logs should generally have the label.

What would be a good API format for “IS NOT SET” clause?

I have a query API against my service, that looks like this (JSON-ish format):
{
filter: {
,attribute2: [val21, val22]
,attribute3: []
}
}
means effectively, select data WHERE attribute2 in ("val21", "val22") AND attribute3 IS NOT NULL in SQL-ish syntax (meaning, the object being returned has attribute 3 set, but I really don't care what its value is. SQL isn't very good at expressing this of course, as my data is key-value store where a key may be "not set" at all instead of being null valued).
I need to expand this API to be able to express IS NOT SET predicate, and I'm at a loss as to what a good way to do so would be.
The only thing I can possibly think of is to add a special "NOT_SET" value in the request API, that would produce NOT SET semantics; but it seems really klunky and hard to grasp:
The API syntax can be thought of as JSON as far as its expressiveness/capability
An ideal answer would reference some well accepted rules on API design, to show that it's "good".
{
filter: {
,attribute2: [val21, val22]
,attribute4: [__NOT_SET__]
}
}
My suggestion would be to move away from trying to use a key-value pair to represent a predicate phrase. You should have a lot more flexibility with a structure similar to:
{
filters: [
{ attribute: "attribute2", verb: "IN", values: [val21, val22] },
{ attribute: "attribute2", verb: "NOT IN", values: [val21, val22] },
{ attribute: "attribute4", verb: "IS NOT SET" },
]
}
You'd want an enum of verbs, of course, and values would have to be optional. You can add more verbs later if you need them, and you're no longer putting quite so much pressure on the poor :. You can also provide to the client a list of supported verbs and how many values (if any) of what type they take, so the client can build the UI dynamically, if desired.
Of course, this is a breaking change, which may or may not be an issue.

Watson Conversation: condition matching input to context array

Taking the car dashboard example, I altered the initial #genre node to be #genre:classical. I also added a list to the contex
"choices":["Beethoven","Mahler 9","Brahms 3rd"]
and the Watson response is "I have 3 selections". The condition on the next node is $choices.contains(input.text). The "Found a match" response is just for testing. It looks like this:
When I test this in the api tool and type "Beethoven" both "Found a match" and "Great choice!..." appear. Same for the other two choices, but only if I type the exact choice, e.g., "Mahler 9". Typing "Mahler" or "mahler" doesn't get a match. I read through the SpEL documentation but couldn't see a way in a one-line condition to parse through the list looking for partial matches.
So my question is, is there an condition expression that would match partial user input, e.g., "Mahler"? I'll be using the Java SDK to code the app server, so alternatively I wondered if I could add a temporary #entity just for this sequence instead of using the context list then delete it when the conversation is done? Or is there a way to construct a more complex condition in the MessageRequest and will Watson recognize it? Or is this just not the right way to go about this? Any pointers, examples or docs much appreciated.
So my question is, is there an condition expression that would match partial user input
You can't add temporary entities or intents. As adding them forces Watson to start training itself (even if you could it through code).
You can however create quite complex regular expressions, pass them in as a context variable.
For example your advanced node can have:
{
"output": {
"text": "Please ask me a question."
},
"context": {
"rx": "fish|[0-9]+"
}
}
Then in you condition you would write.
input.text.matches(context.rx)
This will then trigger if the person mentions a number, or the word fish. So you can create your partial user input checking that way.

APIGEE querying data that DOESN'T match condition

I need to fetch from BaaS data store all records that doesn't match condition
I use query string like:
https://api.usergrid.com/<org>/<app>/<collection>?ql=location within 10 of 30.494697,50.463509 and Partnership eq 'Reject'
that works right (i don't url encode string after ql).
But any attempt to put "not" in this query cause "The query cannot be parsed".
Also i try to use <>, !=, NE, and some variation of "not"
How to configure query to fetch all records in the range but Partnership NOT Equal 'Reject' ?
Not operations are supported, but are not performant because it requires a full scan. When coupled with a geolocation call, it could be quite slow. We are working on improving this in the Usergrid core.
Having said that, in general, it is much better to inverse the call if possible. For example, instead of adding the property when the case is true, always write the property to every new entity (even when false), then edit the property when the case is true.
Instead of doing this:
POST
{
'name':'fred'
}
PUT
{
'name':'fred'
'had_cactus_cooler':true
}
Do this:
POST
{
'name':'fred'
'had_cactus_cooler':'no'
}
PUT
{
'name':'fred'
'had_cactus_cooler':'yes'
}
In general, try to put your data in the way you want to get it out. Since you know upfront that you want to query on whether this property exists, simply add it, but with a negative value. The update it when the condition becomes true.
You should be able to use this syntax:
https://api.usergrid.com/<org>/<app>/<collection>?ql=location within 10 of 30.494697,50.463509 and not Partnership eq 'Reject'
Notice that the not operator comes before the expression (as indicated in the docs).

Resources