I have a situation where I need to check if a vertex with three satisfying properties property1='a',property2='b',property3='c' already exists in a graph and if it does not exist, I need to create it. Basically there should be a unique vertex in the graph with the combination of these three properties. I have tried out this snippet of gremlin code to check based on one property 'id'
getOrCreate = { id ->
def p = g.V('userId', id)
if (p.hasNext()) ? p.next() : g.addVertex([userId:id])
Not very clear about the best way to modify this to achieve what i need with gremlin since I'm a beginner. All I can think of is nesting more if's and else's in the last statement. Any help is appreciated, thank you.
There are several approaches. One way would be to extend your traversal a bit:
getOrCreate = { one, two, three ->
def p = g.V('prop1', one).has('prop2',two).has('prop3',three)
p.hasNext() ? p.next() : g.addVertex([prop1:one,prop2:two,prop3:three])
In the above code, prop1 represents an indexed property, then you just filter on the rest. That prop should be the most selective property in that it should filter out the most results.
If for some reason prop is not selective enough then this solution might not be fast enough. In other words, if you have 1 billion vertices and g.V('prop1', one) returns 100000 then you will be in-memory filtering those, which will be kinda slow. If this is your case, I would consider creating a "poor-man's" composite index, by adding a fourth property to index on that combines all three properties into one. Then just do your lookups on that.
You're almost there.
getOrCreate = { p1, p2, p3 ->
def p = g.V().has('property1', p1).has('property2', p2).has('property3', p3)
p.hasNext() ? p.next() : g.addVertex(['property1':p1,'property2':p2,'property3':p3])
}
Cheers,
Daniel
Related
I would like to use projection queries on AppEngine together with zigzag merge. It appears that this requires the projected property to be included in every index used by the zigzag merge query. In my use case this would result in entity update costs which are too high.
To illustrate, below is a simple example using the Java low-level Datastore API and using the indices Index(E, p1, p3) and Index(E, p2, p3); this works but duplicates the p3 property of entity E in the two indices.
// Create a sample entity with three (indexed) properties.
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
Entity e = new Entity("E");
e.setProperty("p1", 1);
e.setProperty("p2", 1);
e.setProperty("p3", 1);
datastore.put(e);
// Query for the above entity with a projection on property p3.
Query q = new Query("E");
Filter filter1 = new FilterPredicate("p1", FilterOperator.EQUAL, 1);
Filter filter2 = new FilterPredicate("p2", FilterOperator.EQUAL, 1);
q.setFilter(CompositeFilterOperator.and(filter1, filter2));
q.addProjection(new PropertyProjection("p3", Integer.class));
PreparedQuery pq = datastore.prepare(q);
pq.asList(FetchOptions.Builder.withDefaults());
I'd like to remove one of the composite indices, say Index(E, p2, p3), and just rely on the default index for property p2, thus reducing update costs. But doing so results in a DatastoreNeedIndexException at runtime.
Note that a similar problem occurs if I keep the above two indices but add a fourth property to only one of them and include this fourth property in the projection. The use of a default index therefore does not seem to be the problem.
So my question: is there any way of doing projection queries with zigzag merge without duplicating all the projected properties across indices? If not, I'd like to understand what the underlying technical reason is.
Any pointers greatly appreciated.
Ok, so I now see why the projected property needs to be duplicated in all involved indices: because the index sort order has to be the same in all relevant index blocks (two in this example) for zigzag merge to work.
In the example, the last sort order is done on the projected property. When this index is removed it changes the sort order, and a new sort of indexes would be needed for it to work.
So, I don't think what I'm after is possible on AppEngine at the moment. A new dedicated AppEngine feature would be required to enable indexed properties that do not affect index sort order.
https://developers.google.com/appengine/docs/java/datastore/projectionqueries
Why a projected query such as this : SELECT A FROM kind WHERE A = 1 not supported ?
Because it makes no sense. You are asking
SELECT A FROM kind WHERE A = 1
so, give me A where A = 1. Well, you already know that A = 1. It makes no sense for DB to allow that.
The IN query is internally just a series of equals queries merged together, so the same logic applies to it.
The reasoning behind this could be that since you already have the values of the properties you are querying you don't need them returned by the query. This is probably a good thing in the long run, but honestly, it's something that App Engine should allow anyway. Even if it didn't actually fetch these values from the datastore, it should add them to the entities returned to you behind the scenes so you can go about your business.
Anyway, here's what you can do...
query = MyModel.query().filter(MyModel.prop1 == 'value1', MyModel.prop2 == 'value2)
results = query.fetch(projection=[MyModel.prop3])
for r in results:
r.prop1 = 'value1' # the value you KNOW is correct
r.prop2 = 'value2'
Again, would be nice for this to happen behind the scenes because I don't think it's something anybody should ever care about. If I mention a property in a projection list, I'm already stating that I want that property as part of my entities. I shouldn't have to do any more computation to get that to happen.
On the other hand, it's just an extra for-loop. :)
I've got two collections, ObservableCollection<Lap> and a ObservableCollection<Racer> where Lap holds lap data of a car race and Racer, you guess it, the Racer's data. Both objects know the racerId.
Is there a way I can come up with a predicate to use that as a Zip-func to zip those two collections together? The reason I want to do that is to bind them DataGrid.
I had seen this, but can't quite see how to use it with a predicate.
I came up with that:
laps.Zip(participants, (lap, racer) => lap.EnrollmentId == racer.EnrollmentId);
But how would I map that to the DataGridColumns?
I think you are looking for a Join instead, since you do want to combine the properties of both based on a matching Id. For Zip() to work both collections must have the same number of entries in the same matching order already.
var results = from racer in participants
join l in laps
on racer.EnrollmentId equals l.EnrollmentId
select new
{
//select the properties you are interested in here
//or just use both:
Racer = racer,
Lap = l
}
Trying to use Linq with some Entity objects to do a crafty query here. Hoping for some help with a point I'm having a hard time finding decent documentation on:
Basically, I'm trying to use OrderBy to order against the child of an object I'm querying against. The difficult part is that the object has multiple children, and based on the object's type, I need to use one set of a children or another set of children to order by.
To clarify:
A can come in two types: i, or ii
If A is of type i, then I need to order by D: i.e, A has a B, which has many Cs, which has many Ds.
If A is of type ii, then I need to order by F: ie. A has an E, which has many Fs.
So the question is, how can I order by D and F, from A?
I'm hoping for something like:
IQueryable<AObject> aObj = query.OrderBy(aObject=> aObject.Type==i? aObject.B.C.D : aObject.E.F).Skip(offset).Take(limit).AsQueryable();
Of course, I'm also just confused as to how to order the D's, when C has a collection of Ds
Thoughts? And thanks in advance!
You need to use an aggregate function such as Min or Max to pick a value that represents the collection and use that value for the ordering. For example:
IQueryable<AObject> aObj = query.OrderBy(aObject =>
aObject.Type==i ?
aObject.B.Cs.Max(c => c.Ds.Max(d => d.Foo)) :
aObject.E.Fs.Max(f => f.Bar)
).Skip(offset).Take(limit).AsQueryable();
Can someone explain how to define multi column indexes in Grails? The documentation is at best sparse.
This for example does not seem to work at all:
http://grails.org/GORM+Index+definitions
I've had some luck with this, but the results seems random at best. Definitions that works in one domain class does not when applied to another (with different names of course).
http://www.grails.org/doc/1.1/guide/single.html#5.5.2.6%20Database%20Indices
Some working examples and explanations would be highly appreciated!
The solution that has worked for me for multi-column indexes is:
class ClassName {
String name
String description
String state
static mapping = {
name index: 'name_idx'
description index: 'name_idx'
state index: 'name_idx'
}
}
This creates an index called 'name_idx' with the three columns in the index.
Downside: the columns are listed in the index in alphabetical order, not the order that they were entered.
To make your index multi-column, list the columns with comma separator (note, no space after the comma, to avoid this bug. The second URL you point to hits the bug, as it says:
index:'Name_Idx, Address_Index'
with a space; it should work as
index:'Name_Idx,Address_Index'
The first URL you point to was a proposed change (I don't believe it's implemented currently and have no idea how likely it is to ever be).
AFAIK, the index closure shown here was never implemented, so those examples should be ignored (this page is for discussing possible implementations, rather than documenting an actual implementation).
The correct way to define a single-column index name_idx for a name property is
static mapping = {
name index:'name_idx'
}
Sorry, but I don't know how to define a multi-column index, try the Grails mailing list if you don't get an answer here. In the unlikely event that multi-column indices can't be declared directly in the domain classes, you could define them in an SQL file which creates them if they don't already exist (or drops and re-creates them). This SQL file could be executed by the init closure in Bootstrap.groovy
I needed to be able to control the order of the columns in my multi-column index and also make it unique. I worked around the GORM / Hibernate limitations by creating the index in Bootstrap using direct SQL:
class BootStrap {
DataSource dataSource
def init = { servletContext ->
if (!MyModel.count()) { // new database
createIndexes()
...
}
}
private void createIndexes() {
Sql sql = new Sql(dataSource)
sql.execute("create unique index my_index on my_model(col1,col2);")
}