How to automate Node naming in neo4j using loop? - java

I have list of String and i want to import all the elements to the graph database. By saying import i mean, i want to set the String as the Node's property. The size of the list is gonna be massive. So is there any way to automate Node naming ? Because by the traditional way, you have to create Nodes by calling graphDb.createNode() 100 times, if the size of the list is 100.

You can pass your list of strings as a parameter to a Cypher query. Here is a sample snippet:
List<String> names = ...;
try ( Transaction tx = graphDb.beginTx() )
{
String queryString = "UNWIND {names} AS name CREATE (n:User {name: name})";
Map<String, Object> parameters = new HashMap<>();
parameters.put( "names", names );
graphDb.execute( queryString, parameters );
tx.success();
}
Note: If the list of strings is "too long", the above approach will not work, as the server could run out of memory trying to do all that processing in a single transaction. In that case, you may want to use an APOC procedure like apoc.periodic.iterate to create the nodes in smaller batches.

Related

Drools: Get stateless session results using Query

As it comes from the official Drools documentation it is possible to obtain results from stateless session using Query.
// Set up a list of commands
List cmds = new ArrayList();
cmds.add( CommandFactory.newSetGlobal( "list1", new ArrayList(), true ) );
cmds.add( CommandFactory.newInsert( new Person( "jon", 102 ), "person" ) );
cmds.add( CommandFactory.newQuery( "Get People" "getPeople" );
// Execute the list
ExecutionResults results =
ksession.execute( CommandFactory.newBatchExecution( cmds ) );
// Retrieve the ArrayList
results.getValue( "list1" );
// Retrieve the inserted Person fact
results.getValue( "person" );
// Retrieve the query as a QueryResults instance.
results.getValue( "Get People" );
In the sample below, Get People is a drools Query which basically returns an object or a list of objects form a stateless (!) session.
In my project I need to obtain an object created in stateless Kie session, so I've created a Query:
query "getCustomerProfileResponse"
$result: CustomerProfileResponse()
end
The CustomerProfileResponse object is constructing and creating in RHS:
insert(customerProfileResponse);
I wrote the following code to execute commands in batch mode and query the resulted CustomerProfileResponse:
// Creating a batch list
List<Command<?>> commands = new ArrayList<Command<?>>(10);
commands.add(CommandFactory.newInsert(customerProfile));
commands.add(CommandFactory.newQuery(GET_CUSTOMER_PROFILE_RESPONSE,
GET_CUSTOMER_PROFILE_RESPONSE));
// GO!
ExecutionResults results = kSession.execute(CommandFactory.newBatchExecution(commands));
FlatQueryResults queryResults = (FlatQueryResults) results.getValue(GET_CUSTOMER_PROFILE_RESPONSE); // size() is 0!
But queryResults returns an empty list.
I was searching Stack Overflow for the similar questions and find out that it is not possible to run queries against stateless sessions in Drools using batch mode since the session closes immediately after execute() method is called, and the solution is to inject an empty CustomerProfileResponse object along with CustomerProfile in request.
Does anybody can shed some light onto the issue?
Adding CommandFactory.newFireAllRules() after newInsert and before NewQuery should solve the problem. See http://drools-moved.46999.n3.nabble.com/rules-users-Query-in-stateless-knowledge-session-returns-no-results-td3210735.html
Your rules will not fire until the all the command shave been executed. i.e. the implicit fireAllRules() is once all commands have been executed. Which means the query will be invoked before your rule fires to insert the object.
Instead you need to add the FireAllRules command before executing the query.

How to pass a dynamically generated list of property names and values in Neo4j for java?

I'm using the Neo4j driver for java which lets you run a query with parameters. I have a dynamically generated list of strings which act as queries,
with each query having different parameters. Examples of query strings include:
"CREATE (a:Person {id:{id}, name:{name}})"
"CREATE (a:Person {id:{id}, name:{name}}, age:{age}})"
"CREATE (a:Person {id:{id}, age:{age}})"
For each of these queries I would need to pass different parameters with the appropriate values in order for node insertion to work properly.
Code snippet for what I'm trying to do is given below:
try (Transaction tx = session.beginTransaction()) {
String queryStr = "CREATE (a:Person {id:{id}, name:{name}})";
tx.run(query, Values.parameters("id", "testId", "name", "testName"));
}
This piece of code works for non-dynamically generated key-value pairs of properties. For the purpose of this example, I've hardcored the value of
the query string (normally, the transaction would run in a loop and each query string would be read from a list). Now, when attempting to pass
parameters, I can only do so using the syntax above.
For example, the syntax:
try (Transaction tx = session.beginTransaction()) {
String queryStr = "CREATE (a:Person {id:{id}, name:{name}})";
Map<String, String> parameterKeyValueMap = new HashMap<String, String>();
parameterKeyValueMap.put("id", "id");
parameterKeyValueMap.put("name", "testName");
tx.run(query, Values.parameters(parameterKeyValueMap));
tx.success();
}
doesn't work, since the Parameters function requires an even number of arguments. Now, I'm not sure how to actually proceed. Obviously, the
Map object itself would also be dynamically generated (I've just used a simplified example).
Any help/tips would be greatly appreciated!
You want to pass in the Map parameter directly into the run method (as the second parameter), instead of relying on Neo4j's Values interface. There is no need for casting of the Map object into the Values object.
I don’t know Neo4j but CREATE uses executeUpdate in JDBC rather than executeQuery as this is a dB write operation. Query is a dB read operation.

DynamoDB: how to query with multiple filter

I have a table and the structure looks like this:
my table structure
Here correlationId is my hashKey.
I can perform simple query using hashKey:
DynamoDBMapper mapper = new DynamoDBMapper(dynamoDB);
Pickup itemRetrieved = mapper.load(Pickup.class, key);
Now I want to query on basis of fields i.e correlationId, partnerId to get transactionId.
How should I do that?
Here is the sample code with multiple filter.
List<Pickup> pickupList = null;
DynamoDBMapper dynamoDBMapper = new DynamoDBMapper(dynamoDBClient);
Pickup pickup = new Pickup();
pickup.setCorrelationId(correlationId);
Map<String, AttributeValue> attributeValues = new HashMap<>();
attributeValues.put(":partnerId", new AttributeValue(partnerId));
DynamoDBQueryExpression<Pickup> queryExpression = new DynamoDBQueryExpression<Pickup>().withHashKeyValues(pickup)
.withFilterExpression("partnerId = :partnerId")
.withExpressionAttributeValues(attributeValues);
pickupList = dynamoDBMapper.query(Pickup.class, queryExpression);
pickupList.stream().forEach(i -> System.out.println(i.toString()));
Your partition key(correlation Id) is one keys on which you want to retrieve transactionid but it's missing partnerid.
Hence do these 3 steps
Step 1 - build a global secondary index on partnerid
Step 2 - filter on partition id
Step 3 - get transaction id
Query Filtering
DynamoDB’s Query function retrieves items using a primary key or an index key from a Local or Global Secondary Index. Each query can use Boolean comparison operators to control which items will be returned.
With today’s release, we are extending this model with support for query filtering on non-key attributes. You can now include a QueryFilter as part of a call to the Query function. The filter is applied after the key-based retrieval and before the results are returned to you. Filtering in this manner can reduce the amount of data returned to your application while also simplifying and streamlining your code.
The QueryFilter that you pass to the Query API must include one or more conditions. Each condition references an attribute name and includes one or more attribute values, along with a comparison operator. In addition to the usual Boolean comparison operators, you can also use CONTAINS, NOT_CONTAINS, and BEGINS_WITH for string matching, BETWEEN for range checking, and IN to check for membership in a set.
In addition to the QueryFilter, you can also supply a ConditionalOperator. This logical operator (either AND or OR) is used to connect each of the elements in the QueryFilter.

Can I get the string from preparedStatem.setString()?

I have a problem - I create my SQL queries dynamically and basing on user input options. So the user has 5 parameters (actually it's more) and he can choose to use some of them (all if he wants) or none and specify their value in the query. So I construct my query String (basic the WHERE conditions) by checking if a parameter was selected and if a value was provided. However now there is the problem of special characters like '. I could try to use replaceAll("'", "\\") but this is quite dull and I know that preparedStatement.setString() does the job better. However for me I would need than to check again if the parameter was provided and if the previous one were also (to specify the poison of ? and connect it to the right parameter). This causes a lot of combinations and does not look elegant.
So my question is - can I somehow receive the string preparedStatement.setString() produces? Or is there a similar function that would do the same job and give me the String so I can put it in the query manually.
Maybe the intro was too long but someone might have a better idea and I wanted to explain why I need it.
What you can do is construct the basic, unparameterized SQL query based on whether the parameters were specified, and then use the prepared statement to fill in the parameters.
It could look something like this (rough sketch):
Map<String, Object> parameterValues = /*from user*/;
List<String> parameterNames = Arrays.asList("field1", "field2", "field3");
List<Object> valueList = new ArrayList<Object>();
StringBuilder statementBuilder = new StringBuilder("select * from table where ");
for ( String parameterName : parameterNames ) {
if ( parameterValues.containsKey(parameterName) ) {
statementBuilder.append(parameterName + " = ? AND");
valueList.add(parameterValues.get(parameterName));
}
}
PreparedStatement st = conn.prepareStatement(statementBuilder.toString(),
valueList);
//set each parameter here.
It's only hard the first time; then you can make it generic. That said there are probably query builders that abstract all of this away for you. I use QueryDSL but that does not have bindings for pure JDBC but rather JPA and JDO, etc.
On another forum I was given a different, simpler and cleaner approach that work perfectly.
Here are some links for others with the same problem:
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1669972300346534908
http://www.akadia.com/services/dyn_modify_where_clause.html

grouping data in java

is there someway we can group similar data in java?
i want to group all the data with same id and print it out.
i am querying for the data using jdbc and was searching for a library i could use for this.
any idea?
thanks
Use a Map<GroupID, List<Data>>.
Map<Long, List<Data>> groups = new HashMap<Long, List<Data>>();
while (resultSet.next()) {
Long groupId = resultSet.getLong("groupId");
String col1 = resultSet.getString("col1");
String col2 = resultSet.getString("col2");
// ...
List<Data> group = groups.get(groupId);
if (group == null) {
group = new ArrayList<Data>();
groups.put(groupId, group);
}
group.add(new Data(groupId, col1, col2 /* ... */));
}
You could also just make it a property of another (parent) bean.
See also:
Collections and Maps tutorial
Ideally you should use a where clause in your SQL query to limit the returned data to the id in question:
select *
from table
where id = 'xxxxxx'
Of course if you will be printing out the data for all id's this may be a bad choice, as then your app will perform multiple sql queries, which usually will result in a performance hit.
As for grouping data in Java, take a look at java.util.HashMap (or any of the container classes that implement the Map interface). HashMap is a container of key-value pairs. In your case, the 'key' can be a String (or whichever data type applies) representing your id, and the 'value' can be an object to contain the data associated to the id key (i.e.: ArrayList of Strings, or a new class you define to help you manage the data)
Are you looking for the SQL ORDER BY clause?
SELECT columns
WHERE criteria
ORDER BY id ASC;
That will give you all the data in your criteria and will order it by the id column which naturally means that all the rows with the same id will appear consecutively.

Categories