Adding a relationship to an index in neo4jclient - neo4j

This might be real newbie question but please bear with me as I am new. I looked at this code sample in documentation.
graphClient
.Cypher
.Start(new {
n1 = "custom",
n2 = nodeRef,
n3 = Node.ByIndexLookup("indexName", "property", "value"),
n4 = Node.ByIndexQuery("indexName", "query"),
r1 = relRef,
moreRels = new[] { relRef, relRef2 },
r2 = Relationship.ByIndexLookup("indexName", "property", "value"),
r3 = Relationship.ByIndexQuery("indexName", "query"),
all = All.Nodes
});
In the example above I would like to get a relationship by IndexLookup. So I created a Relationship Index
_graphClient.CreateIndex("item_relationship_idx", new IndexConfiguration
{
Provider = IndexProvider.lucene,
Type = IndexType.exact
},
IndexFor.Relationship);
Question - How do I get a relationship created by _graphClient.CreateRelationship into an index. Most of the samples provided just show getting NodeReference into an Index. I am sure I am missing something obvious. Any help would be appreciated.

Update to Neo4jClient 1.0.0.568 or above and you'll find the (new) support for relationship indexing, consistent with how node indexing works.
(You should also look at Neo4j 2.0 and try and use the new indexing infrastructure though. No point writing new code against old approaches.)

Update to Neo4jClient 1.0.0.568 or above and you'll find the (new) support for relationship indexing, consistent with how node indexing works.
Does that mean I can use the Create method or do I still need the CreateRelationship method? I have Neo4jClient 1.0.0.590 but I don't find it that obvious.

Related

Spring data elasticsearch - Aggregations in new version

We have been using spring-data-elasticsearch for 4.1.13 until recently for querying from elastic search. For grouping something we used aggregations
Consider a index of books. For each book there can be one or multipe authors
To get count of books by author we used TermsAggregationbuilder to get this grouping as shown below
SearchSourceBuilder builder = this.getQuery(filter, false);
String aggregationName = "group_by_author_id";
TermsAggregationBuilder aggregationBuilders =
AggregationBuilders.terms(aggregationName).field("authors");
var query =
new NativeSearchQueryBuilder()
.withQuery(builder.query())
.addAggregation(aggregationBuilders)
.build();
var result = elasticsearchOperations.search(query, EsBook.class, ALIAS_COORDS);
if (!result.hasAggregations()) {
throw new IllegalStateException("No aggregations found after query with aggregations!");
}
Terms groupById = result.getAggregations().get(aggregationName);
var buckets = groupById.getBuckets();
Map<Long, Integer> booksCount = new HashMap<>();
buckets.forEach(
bucket ->
booksCount.put(
bucket.getKeyAsNumber().longValue(), Math.toIntExact(bucket.getDocCount())));
return booksCount ;
We recently upgraded to spring-data-elasticsearch 4.4.2 and saw that there are some breaking changes.
First .addAggregations were replaced by withAggregations
Second unlike before I cant seem to directly get Terms and buckets after querying as
result.getAggregations().get(aggregationName); is no more possible and only other option I see is result.getAggregations().aggregations(). So am wondering if anyone has done the same. The documentation itself is so poor in Elastic search.
First .addAggregations were replaced by withAggregations
addAggregation(AbstractAggregationBuilder<?>) has been deprecated and should be replaced by withAggregations. This is not a breaking change.
The change in the returned value for SearchHits.getAggregations() is documented in the migration guides from 4.2 to 4.3 "Removal of org.elasticsearch classes from the API."
So from 4.3 on result.getAggregations().aggregations() returns the same that previously result.getAggregations() returned.

Breeze Predicate in sub query

I have two entities, let's call them Alpha and Beta.
There is a one to many relationship between them, such that Beta has a foreign key to Alpha, MyAlphaId, and thus a reference property MyAlpha.
I have a predicate being built for Alphas.
e.g.
var predicateAlpha = new Predicate('name', 'contains', 'somevalue');
I want to then "transpose" this onto a query for Beta's where its myAlpha property matches that predicate.
e.g.
var predicateBeta = new Predicate('myAlpha', 'in', predicateAlpha);
I am aware of the ability for me to construct the predicate in the following manner:
var predicateBeta = new Predicate('myAlpha.name', 'contains', 'somevalue');
My issue is that I don't know what that predicate may be. I can't just pre-pend 'myAlpha.' as it may include an OData function such as 'concat('somefield', 'someotherfield')'.
Any other thoughts or suggestions on how I can achieve this?
For me, it would make sense for IN to accept a predicate that allows this to happen... I can't see the source code accepting a predicate so I can't think how else to make this happen...
Assuming that Alpha has a property betas, you could query for Alphas using the predicate, and expand the Betas so that they are brought in too. Then collect the Betas if you need them in a single list:
var query = em.createQuery(predicateAlpha).expand('betas');
var betas = [];
em.executeQuery(query).then(queryResult => {
queryResult.results.forEach(alpha => {
betas = betas.concat(alpha.betas);
});
});

How to create multiple node via looping in py2neo for neo4j

Kindly help me to resolve this issue. I am following the tutorial on this link: https://www.kernix.com/blog/an-efficient-recommender-system-based-on-graph-database_p9 . I am unable to modify the following so that it could comply with the new format of py2neo v3 where graph.run is used instead of graph.cypher.begin(). The purpose of the code below is to Create the nodes relative to Users, each one being identified by its user_id and "MERGE" request : creates a new node if it does not exist already
tx = graph.cypher.begin()
statement = "MERGE (a:`User`{user_id:{A}}) RETURN a"
for u in user['id']:
tx.append(statement, {"A": u})
tx.commit()
Thank you very much in advance
With v3 of py2neo your snippet would look like this:
tx = graph.begin()
statement = "MERGE (a:`User`{user_id:{A}}) RETURN a"
for u in user['id']:
tx.run(statement, {"A": u})
tx.commit()
begin() is a method on the Graph class, which will create a new transaction.
Transaction.run will send a Cypher statement to the server for execution - but not commit the transaction until Transaction.commit is called.

Problem creating an Entity object/queryable from the result of a LINQ join in MVC

I'm attempting to write a search function for a database table that needs to access information from related tables using Entity Framework. However, I'm running into problems getting the data back out of my initial query after doing a join on the parent table and the related tables. My code currently looks like this. I initialize my queryable object
IQueryable<PurchaseOrder> po = _context.PurchaseOrders;
Where PurchaseOrder is an Entity type. Then there is a series of blocks like this.
if (!String.IsNullOrEmpty(searchViewModel.Comment)){
var helper = _context.PurchaseOrderComments.Where(x => x.CommentText.Contains(searchViewModel.Comment));
var mid = po.Join(helper, r => r.PurchaseOrderID, u => u.PurchaseOrderID, (r, u) =>
new
{
PurchaseOrderID = r.PurchaseOrderID,
PurchaseOrderNumber = r.PurchaseOrderNumber,
VendorID = r.VendorID,
ContractNumber = r.ContractNumber,
BuyerUserID = r.BuyerUserID
});
po = mid.Select(x => new PurchaseOrder
{
PurchaseOrderID = x.PurchaseOrderID,
PurchaseOrderNumber = x.PurchaseOrderNumber,
VendorID = x.VendorID,
ContractNumber = x.ContractNumber,
BuyerUserID = x.BuyerUserID
});
}
After each block, po is passed to the next search parameter. However, as you might guess, my program complains that I can't build a complex type in mid's Select statement. I've also tried building PurchaseOrder objects from the contents of mid, inserting them into a new List of PurchaseOrders, and converting that list into a queryable to assign to po to pass on to the next block. However, that changes po's data type from System.Data.Object.ObjectSet to System.Collections.Generic.List, which then throws an InvalidOperationException the next time I try and iterate through it using a foreach.
So my question is, are there any obvious mistakes in my approach or any suggestions for other ways to approach the problem? Thanks very much for any help.
I think you're making this more complicated than it needs to be. If I understand what you're trying to do, you should be able to do something like this:
if (!String.IsNullOrEmpty(searchViewModel.Comment)){
po = po.Where(
o => o.PurchaseOrderComments.Any(
c => c.CommentText.Contains(searchViewModel.Comment)));
}
StriplingWarrior's solution is the best way. In case that your PurchaseOrder class really doesn't have a navigation collection of PurchaseOrderComments (which would force you to use a join) the following should work and is simpler as your double projection:
po=po.Join(helper, r => r.PurchaseOrderID, u => u.PurchaseOrderID, (r, u) => r);

NHibernate QueryOver: How to join unrelated entities?

I have the following query working which gets the results I want:
int associatedId = 123;
MyObject alias = null;
var subQuery = QueryOver.Of<DatabaseView>()
.Where(view => view.AssociatedId == associatedId)
.And(view => view.ObjectId == alias.ObjectId)
.Select(view => view.ObjectId);
var results = session.QueryOver<MyObject>(() => alias)
.WithSubquery.WhereExists(subQuery)
.List();
The DatabaseView has been mapped as an actual NHibernate entity (so I can use it with QueryOver), but it is not associated to MyObject in the HBM mappings.
This query returns an IList<MyObject> using a SELECT ... FROM MyObject WHERE EXISTS (subquery for DatabaseView here). How can I re-write this to return the same data but using a JOIN instead of sub query?
In NHibernate 5.1+ it's possible for QueryOver/Criteria via Entity Join:
int associatedId = 123;
MyObject alias = null;
DatabaseView viewAlias = null;
var results = session.QueryOver<MyObject>(() => alias)
.JoinEntityAlias(() => viewAlias, () => viewAlias.ObjectId == alias.ObjectId && viewAlias.AssociatedId == associatedId)
.List();
Criteria example:
int associatedId = 123;
var results = session.CreateCriteria<MyObject>("alias")
.CreateEntityAlias(
"viewAlias",
Restrictions.EqProperty("viewAlias.ObjectId", "alias.ObjectId")
&& Restrictions.Eq("viewAlias.AssociationId", associatedId),
JoinType.InnerJoin,
typeof(DatabaseView).FullName)
.List();
You can join onto unrelated entities with Linq in NHibernate 3+
Funnily enough you use the join query expression element:
from type1 in Repository.Query<MyType1>()
join type2 in Repository.Query<MyType2>()
on type1.Id equals type2.Id
Note: Repository.Query is just returning an IQueryable Query from the session
I'm hoping there is a solution for QueryOver as I don't always want to model two-way relationships in my domain but they are still useful for querying.
Also, you can map a Access="noop" 2 way relationship using Criteria API without putting into your POCO classes:
http://ayende.com/blog/4054/nhibernate-query-only-properties
I realize this question is 5 years old, and the "correct" answer is definitely that you can't do this with QueryOver, as the other answers indicate. However, if you really need this functionality (as I did), there is a decent workaround that I found.
The solution is to use a "loader query" with native SQL in your mapping XML to produce a related collection (see http://nhibernate.info/doc/nhibernate-reference/querysql.html#querysql-load). In the OP's specific example, you would go ahead and map your DatabaseView as an entity as suggested, and then write the following in your mapping:
<class name="MyObject"...>
...
<set name="MyViews" inverse="true">
<key column="ObjectId" foreign-key="none"/>
<one-to-many class="MyObject"/>
<loader query-ref="myObjectViewsLoadQuery"/>
</set>
</class>
Then we just need to define our named myObjectViewsLoadQuery in raw SQL to explain to NH how to join the two:
<sql-query name="myObjectViewsLoadQuery">
<load-collection alias="view" role="MyObject.MyViews"/>
SELECT view.*
FROM DatabaseView view
WHERE view.ObjectId = :id
</sql-query>
We can now pretend like there is a "real" collection named MyViews relating MyObject to DatabaseView in our query:
MyObject alias = null;
DatabaseView view = null;
var results = session.QueryOver<MyObject>(() => alias)
.JoinAlias( () => alias.MyViews, () => view )
//.Where( () => view.Property == "myValue" ) // optionally, restrict the view etc.
.List();
Certainly, this is a lot of trouble to go through if you only care about an "elegant" query. However, if the reason you are using QueryOver is that you want to be able to accept arbitrary input Expressions to filter your DatabaseView by, or various similar activities, this works very nicely.

Resources