I want to writing 'friends of friend' traversal using AQL
I have a Collection with Name:User and a edge Collection with name Conatct.
my Conatct documents:
I also read this article that implement friends of friend in ArangoDb, but that's post Uses functions of lower version of ArangoDB that used GRAPH_NEIGHBORS() function.
in ArnagoDB 3.0(latest version), GRAPH_NEIGHBORS() function have been removed!
now, how can I implement fof using Aql in ArnagoDB 3.0 ?
thanks a lot
The graph functions have been removed, because there is the more powerful, flexible and performant native AQL traversal, which was introduced with 2.8, and extended and optimized for version 3.0.
To retrieve friends of friends, a traversal starting at the user in question with a traversal depth = 2 is needed:
LET user = DOCUMENT("User/#9302796301")
LET foaf = (
FOR v IN 2..2 ANY user Contact
RETURN v // you might wanna return the name only here
)
RETURN MERGE(user, { foaf } )
The document for the user with _key = #9302796301 is loaded and assigned to a variable user. It is used as start vertex for a traversal with min and max depth = 2, using the edges of the collection Contact and ignoring their direction (ANY; can also be INBOUND or OUTBOUND). The friends of friends documents are fully returned in this example (v) and merged with the user document, using the attribute key "foaf" and the value of the variable foaf.
This is just one simple example how to traverse graphs and how to construct result sets. There are many more options of course.
Related
I recently started using Arango since I want to make use of the advantages of graph databases. However, I'm not yet sure what's the most elegant and efficient approach to query an item from a document collection and applying fields to it that are part of a relation.
I'm used to make use of population or joins in SQL and NoSQL databases, but I'm not sure how it works here.
I created a document collection called posts. For example, this is a post:
{
"title": "Foo",
"content": "Bar"
}
And I also have a document collection called tags. A post can have any amount of tags, and my goal is to fetch either all or specific posts, but with their tags included, so for example this as my returning query result:
{
"title": "Foo",
"content": "Bar",
"tags": ["tag1", "tag2"]
}
I tried creating those two document collections and an edge collection post-tags-relation where I added an item for each tag from the post to the tag. I also created a graph, although I'm not yet sure what the vertex field is used for.
My query looked like this
FOR v, e, p IN 1..2 OUTBOUND 'posts/testPost' GRAPH post-tags-relation RETURN v
And it did give me the tag, but my goal is to fetch a post and include the tags in the same document...The path vertices do contain all tags and the post, but in separate arrays, which is not nice and easy to use (and probably not the right way). I'm probably missing something important here. Hopefully someone can help.
You're really close - it looks like your query to get the tags is correct. Now, just add a bit to return the source document:
FOR post IN posts
FILTER post._key == 'testPost'
LET tags = (
FOR v IN 1..2 OUTBOUND post
GRAPH post-tags-relation
RETURN v.value
)
RETURN MERGE(
post,
{ tags }
)
Or, if you want to skip the FOR/FILTER process:
LET post = DOCUMENT('posts/testPost')
LET tags = (
FOR v IN 1..2 OUTBOUND post
GRAPH post-tags-relation
RETURN v.value
)
RETURN MERGE(
post,
{ tags }
)
As for graph definition, there are three required fields:
edge definitions (an edge collection)
from collections (where your edges come from)
to collections (where your edges point to)
The non-obvious vertex collections field is there to allow you to include a set of vertex-only documents in your graph. When these documents are searched and how they're filtered remains a mystery to me. Personally, I've never used this feature (my data has always been connected) so I can't say when it would be valuable, but someone thought it was important to include.
I'm trying to move "complex" function to Azure Search. This function calculates score per each result element base on filter data (from search query) and data stored in result element. Score is use for reasult boosting. Base on my research Azure Search provides result boosting, but it's too simple for mine requirement.
Example function:
//filterElementsIds - ids taken from search query filter
public double Score(IEnumerable<string> filterElementsIds, ResultElement element)
{
double score = 0;
foreach(var elem in element.ScoreForFilters)
if (filterElementsIds.Any(x => x == elem.Key))
score += elem.Value * 1.5;
return score;
}
Currently, I'm iterating through each result returned by Azure Search - calculating score and sorting elements inside my application.
Is it possible to implement such function in Azure Search to improve process of boosting results?
I'm not sure I fully understand your question, but it appears like you are trying to boost the score of certain document if their key is equal to any of the IDs in your collection of "filterElements". If that's so, you could use the lucene query language to craft a query which does that:
https://learn.microsoft.com/en-us/azure/search/search-query-lucene-examples
You could do a search that looks like this
OriginalSearchTerm OR (OriginalSearchTerm AND key:("filterID1" OR "filterID2" OR "filterID3"))
That way, documents that match both the original search term as well as having one of the filter ID as part of the "key" field will match higher than documents that only match the original search term. You can also term boosting to give a specific boost to the key field in this case
If that's so, could you use "term boosting" to achieve this?
https://learn.microsoft.com/en-us/azure/search/search-query-lucene-examples#example-5-term-boosting
OriginalSearchTerm OR (OriginalSearchTerm AND key:("filterID1" OR "filterID2" OR "filterID3")^2)
I'm interested in using traversals to quickly find all the documents linked to an initial document. For this I'd use:
let id = 'documents/18787898'
for d in documents
filter d._id == id
for i in 1..1 any d edges
return i
This generally provides me with all the documents related to the initial ones. However, say that in these edges I have more information than just the standard _from and _to. Say it also contains order, in which I indicate the order in which something is to be displayed. Is there a way to also grab that information at the same time as making the traversal? Or do I now have to make a completely separate query for that information?
You are very close, but your graph traversal is slightly incorrect.
The way I read the documentation, it shows that you can return vertex, edge, and path objects in a traversal:
FOR vertex[, edge[, path]]
IN [min[..max]]
OUTBOUND|INBOUND|ANY startVertex
edgeCollection1, ..., edgeCollectionN
I suggest adding the edge variable e to your FOR statement, and you do not need to find document/vertex matches first (given than id is a single string), so the FOR/FILTER pair can be eliminated:
LET id = 'documents/18787898'
FOR v, e IN 1 ANY id edges
RETURN e
I have this path
(user)-[like]->(book)
Now I want to get a list of all books with all users that liked a book
USER BOOK
[user, user] book
[] book
[user] book
I have only found examples with a starting point but in this case there isn't.
Under the assumption that you have created a document collection book and user and a edge collection like:
FOR b IN book
LET u = (FOR v IN 1 INBOUND b ##edgeCol RETURN v)
RETURN { book: b, user : u }
The ##edgeCol is a bind parameter and has to contain the name of your edge collection (in your case like).
This query should return you an array of documents with field book which includes your book document and an array user with all user documents who likes the book. If the query returns you an empty array of users for each book, you probably have to change the direction INBOUND in the query to OUTBOUND depending on the direction of your edges.
For more information about graph traversals in AQL you should take a look into the docs.
I am using ArangoDB 2.8
I am doing a traversal query that includes 2 different collections. However in my result I would like to get only a particular collection, but I don't see the way to filter by collection name.
In my case I have address collection and user collection. In address collection I distinguish 3 levels as: {addressType: state}, {addressType: city} and {addressType: street}. Then I have an edge that links from address to user collection (state>city>street>user). I want to do a traversal (like in the code below) from an address (of any type) to the user (if any) and only return the collection of type user -for example if a street does not have a link to a user then return empty-.
For p in TRAVERSAL(address, myEdge, #vertex_id, 'outbound', {paths:false})
RETURN p.vertex._id)
Another answer is using the IS_SAME_COLLECTION function as hinted by this SO answer:
FOR p IN TRAVERSAL(address, myEdge, #vertex_id, 'outbound', {paths:false})
FILTER IS_SAME_COLLECTION('user', p.vertex._id)
RETURN p.vertex._id)
or, since TRAVERSAL was removed in ArangoDB 3.0+ (see this answer and the migration guide), something like
FOR v IN 0..5 IN OUTBOUND #vertex_id myEdge
FILTER IS_SAME_COLLECTION('user', v._id)
RETURN v._id)
Well I had to find a solution, so here is mine (I know is not the best but worked for me):
What I do is split the _id by "/" and check whether the first part (collection name) is in ['user']
For p in TRAVERSAL(address, myEdge, #vertex_id, 'outbound', {paths:false})
FILTER (SPLIT(p.vertex._id, "/", 1)[0]) IN ['user']
RETURN p.vertex._id)