Cypher and query templates / string substitution - neo4j

I worked a lot with MyBatis and I used very often string substitution to write less distinct queries: there, you can use #{} for PARAMETERS and ${} for plain string substitution (e.g. I want that a section of the query is calculated at runtime by the business logic).
Now, I would like to do the same in a Cypher repository in Spring (ReactiveNeo4jRepository): I have a very complex query, and I would define at runtime a section of a statement, that can have 2 different "versions" for privileged and unprivileged users. This is only a small section of a very complex statement, and so it would be much better than defining two different queries.
But I can't find anything similar to MyBatis string substitution... is there a way to accomplish what I'm trying to do?

Related

Is there a way in SumoLogic to store some data and use it in queries?

I have a list of IPs that I want to filter out of many queries that I have in sumo logic. Is there a way to store that list of IPs somewhere so it can be referenced, instead of copy pasting it in every query?
For example, in a perfect world it would be nice to define a list of things like:
things=foo,bar,baz
And then in another query reference it:
where mything IN things
Right now I'm just copying/pasting. I think there may be a way to do this by setting up a custom data source and putting the IPs in there, but that seems like a very round-about way of doing it, and wouldn't help to re-use parts of a query that aren't data (eg re-use statements). Also their template feature is about parameterizing a query, not re-use across many queries.
Yes. There's a notion of Lookup Tables in Sumo Logic. Consult:
https://help.sumologic.com/docs/search/lookup-tables/create-lookup-table/
for details.
It allows to store some values (either manually once, or in a scheduled way as as a result of some query) with | save operator.
And then you can refer to these values using | lookup which is conceptually similar to SQL's JOIN.
Disclaimer: I am currently employed by Sumo Logic.

Neo4j Cypher single query performance vs separation the same query on two different queries

I think I'm doing something wrong, but I noticed that sometimes it is better to divide the single query on two separate queries and pass the result of the first one as a parameter to the second query. Doe this make sense? Is there any magic under the hood for external parameters vs query variable passed from one part of the same query to another part?
Yes, it makes sense, although you can chain parts of your queries together using WITH. When you do that, make sure that you watch the cardinality, especially when you have UNWIND clauses.
When you decide to use multiple queries, and depending on their type (as in WRITE / READ ) it may be smart to make sure that, in the case of a WRITE query, they are all part of the same transaction. See https://neo4j.com/docs/cypher-manual/4.0/introduction/transactions/

How does path search work on Cypher and what types of filtering can be done during expansion?

I'm trying to understand Neo4j's mechanics when dealing with path searches. I studied the query patterns and execution plan operators in the developer manual, but I still have some questions.
Please correct me if I'm wrong, but from the content I read, and from some posts on Neo4j's blog, I understood that Cypher and Java traversals generally perform depth-first searches, more specifically informed searches, and that variable-length queries fit into it. I also read that shortest path planning uses a breadth-first bidirectional search, and a depth-first search as a fallback.
Is there any way to perform breadth-first searches in Neo4j other than that?
I know the APOC procedures library allows this kind of search through path expanders, but I'm limiting my scope to just the Cypher language for now.
Also, does the variable-length pattern run recursively?
And what kinds of filtering are executed during expansion? I read that functions like ALL normally are checked during expansion, but some are executed later.
The reason for these questions is to see to what extent I would be able to manipulate the data and make complex traversals using only Cypher and what already comes with Neo4j, without external libraries and without having to write procedures through the API.
Forgive me if these questions are trivial. Thanks in advance.
Being a declarative query language Cypher doesnot controls how the underlying engine will search the pattern. So by just specifying a pattern we cannot specify which pattern matching algorithm shall be used for finding patterns. So we cannot perform breath first algorithm with just using Cypher.
For running a variable length pattern recursively we can use kleene star over single edge labels for example :KNOWS* or we can use the or operator in cypher for example :KNOWS|FOLLOWS* in cypher. Essentially this means (KNOWS|FOLLOWS)* in Regular Path Query (RPQ) format. Which is equivalent to (a|b)* in regular expression syntax. We can also have more edge labels such as (a|b|c|....)* in cypher.
We can also specify a varibale length over the pattern as ()-[:KNOWS|FOLLOWS*1..6]->() in cypher.
However we cannot do recursive iterations over a few pattern for example a sub-graph which has a node with one incoming edge and atleast two out going edges from the same node. for example a pattern such as this (a)-[r]->(b)-[s]->(c), (b)-[v]->(d). This is an example of a conjunctive pattern.
Filtering can be is normally performed in the WHERE clause based on the property key value pairs. We can set the labels in the pattern expressed in the MATCH clause so that the underlying engine knows the start node. For example as done in the following query
match (a:Person{name:'Keanu Reeves'})-[r]->(b) return * limit 5

How do a general search across string properties in my nodes?

Working with Neo4j in a Rails app.
I have nodes with several string properties containing long strings of user generated content. For example in my nodes of type: "Book", I might have properties, "review", and "summary", which would contain long-form string values.
I was trying to design queries that returned nodes which match those properties to general language search terms provided by a user in a search box. As my query got increasingly complicated, it occurred to me that I was trying to resolve natural language search.
I looked into some of the popular search gems in Rails, but they all seem to depend on ActiveRecord. What search solutions exist for Neo4j.rb?
There are a few ways that you could go about this!
As FrobberOfBits said, Neo4j has what are called "legacy indexes" which use Lucene it the background to provide indexing of generic things. It does support the new schema indexes. Unfortunately those are based on exact matches (though I'm pretty sure that will change in Neo4j 2.3.x somewhat).
Neo4j does support pattern matching on strings via the =~ operator, but those queries aren't indexed. So the performance depends on the size of your database.
We often recommend a gem called searchkick which lets you define indexes for Elasticsearch in your models. Then you can just call a Model.search method to do your searches and it will first query elasticsearch to get the node IDs and then load those nodes via Neo4j.rb. You can use that via the neo4j-searchkick gem: https://github.com/neo4jrb/neo4j-searchkick
Lastly, if you're doing NLP and are trying to extract important words from your text, you could create a Tag/Word label and create relationships from your nodes to these NLP extracted nodes so that you can search based on those nodes in the future. You could even build recommendations from one text node to another based on the number/type of common tag nodes.
I don't know if anything specific exists for neo4j.rb and activerecord. What I can say is that generally this stuff is handled through the use of legacy indexes that are implemented by Lucene.
The premise is that you create a lucene-managed index on certain properties, and that then gives you access to use the Lucene query language via cypher to get data from those indices. Relative to neo4j.rb, it doesn't look any different than running cypher queries, like this:
START item=node:node_auto_index("(title:'foo bar' AND body:baz*) OR title:'bat'")
RETURN item
Note that lucene indexes and that query language can only be used in a START block, not a MATCH block. Refer to the Lucene Query Syntax to discover more about what you can do with that query syntax (fuzzy matching, wildcards, etc -- quite a bit more extensive than what regex would give you).

Esper - how to build dissent "statement factory"?

using Esper engine - I find myself write lots of String SQLs, and do lots of string actions to insert query to EPStatement object.
What is the best practice to build queries in more convenient way? maybe build queries not with pure strings but with objects? (Have anyone used EPManagedStatement object?)
There is also the Statement Object Model.
With these classes you can build statements in a more object-oriented way and avoid all the string queries.
Taken from the documentation:
The statement object model is a set of classes that provide an object-oriented representation of an EPL or pattern statement. The object model classes are found in package com.espertech.esper.client.soda. An instance of EPStatementObjectModel represents a statement's object model.
The statement object model classes are a full and complete specification of a statement. All EPL and pattern constructs including expressions and sub-queries are available via the statement object model.
If you find that you are writing a lot of free-form EPL that only varies greatly by the actual values you are inserting, one approach you might find lightens up the amount of code is to use prepared statements ( (EPPreparedStatement). That way, you write the EPL once and then simply issue binds without having to re-specify the text all over again.

Resources