Grails searchable plugin - grails

In my Grails app, I'm using the Searchable plugin for searching/indexing. I want to write a Compass/Lucene query that involves multiple domain classes. Within that query when I want to refer to the id of a class, I can't simply use 'id' because all classes have an 'id' property. Currently, I work around this problem by adding the following property to a class Foo
public Long getFooId() {
return id
}
static transients = ['fooId']
Then when I want to refer to the id of Foo within a query I use 'fooId'. Is there a way I can provide an alias for a property in the searchable mapping rather than adding a property to the class?

You can give a more specific name to your id property. See this page for how to do this.

I finally discovered that this is the way to do it:
static searchable = {
id: name 'fooId'
}

Thanks! This would work really well, that is, if I could get past the OOM errors the app server seems to throw each time Searchable plugin is installed. These are bubbling up via :
org.compass.gps.CompassGpsException: Failed to index, execution exception; nested exception is java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError: Java heap space
Has anyone configured their Searchable.groovy in grails-app/conf to perform a strict file:/// or mmap:// only configuration using no heap, and indexing say once or twice per day? Search is beyond a nice to have - but the cost of using the database mirroring in Grails (with Oracle 10g) seems memory intensive.
Really small amount of domains to search (4) small database, maybe 1-2gb for this application.

Related

Grails dynamic "inList"

This is almost identical to this old question: Dynamic define the inList constraint using database query which was essentially unaddressed, perhaps there have been advances in the years since that was asked.
I'd like to populate the inList parameter of a domain attribute with values from another domain. Due to auto-generated views (scaffolding, filterpane), this needs to come from inList rather than a custom validator.
class MyDomain {
String someValue
static constraints = {
someValue(nullable: true, maxSize: 50, inList: SomeOtherDomain.list()*.name)
}
}
This gives the following error on startup:
Caused by: java.lang.IllegalStateException: Either class [thepackage.SomeOtherDomain] is not a domain class or GORM has not been initialized correctly or has already been shutdown. Ensure GORM is loaded and configured correctly before calling any methods on a GORM entity.
I know, the "correct" way to handle this is to make someValue an instance of SomeOtherDomain instead of just storing the name, but that doesn't quite fit. We want to be able to delete an instance of SomeOtherDomain without breaking the saved value of the owning domain... the domain with the deleted value will be invalid going forward, and would have to be updated before saving, but archived/locked records will still exist and can be displayed.
You can specify value lists for filterpane like this:
<filterpane:filterPane domain="MyObject" filterPropertyValues="${['someValue':[values: SomeOtherDomain.list().collect{it.name}]]}" />
And then just use a custom validator to actually validate. I'm not sure what scaffolding might use the inList but easy enough to get around that if you're OK with replacing a few scaffolded pages with static ones.

Restrict search to specific domains

I'm using the elasticsearch plugin and I'm running searches using elasticSearchService.search(myKeywords) which searches for keywords over all the domain classes marked as searchable.
Now I want to restrict the search to two specif domain classes. I can see there are options named indices and types that can be passed to the search method, but if I simply use my domain class names on them I get errors telling the index or type doesn't exist. What exactly should I do to achieve what I want?
(I'm new to lucene and elasticsearch and I'm not sure I understood the index and type concepts. Reading the docs I could only find examples to restrict searches to an specific field, not a hole domain class or whatever it is mapped to, in lucene/elasticsearch concepts).
The way to go is:
elasticSearchService.search(myKeywords, [types:["myPackage.MyClass","myPackage.MyOtherClass"]])
The results are as expected, but I'm still worried about having one index (and one type) per domain. Not what I expected but I can't see how to map all domain classes to a single index for the hole database as stated by the docs

Mapping Queries result set to domain objects in SDN 3.3.1.RELEASE

I have created a POC with SDN 3.3.1 in which I have deployed a plugin inside the Neo4j server. The plugin contains domain objects, repositories and controllers.
From my application, I'm making rest calls to the controllers to execute repositories methods and return the response.
The issue is that in my queries, I'm returning multiple nodes and relationships. So, to map the response, I created wrapper classes using #QueryResult, #ResultColumn containing references to domain objects for each query. This is because each query has a different result set.
Since, my application has around 150 such queries I will have to create similar number of intermediate wrapper classes.
This is quite tedious and number of wrapper classes will only increase in future as more and more queries are added.
Is there any smarter way to do this?
I tried to have all of my domain objects as references in a single wrapper class. So that I can use it for any of my queries. But it gives exception if any of the fields in the wrapper class is not present in the query result.
Another issue is that, some of my queries are written to return all different nodes connected to a particular node, e.g,
Match (a)-[rel]->(b)-[tempRel]->(tempNodes) Return b,tempRel,tempNodes
I'm not sure how to map this result set to a wrapper class.
Is there any way to achieve it without refactoring the queries to match indvidual paths?
Regards,
Rahul
Good idea to have it ignore unknown classes and fields in both directions perhaps as an additional annotation on the class can you raise a Spring JIRA issue?
something like this e.g.
#QueryResult(requireFields=false, require=false)
class MyResult {
String name;
int age;
}
but you still have them focused on one area or use-case and not 1 for all 150 use-cases but perhaps 15-30 different ones.

How can we create our own custom validation

I am using grails 2.4.3 with database Neo4j with SDN ,We don't use Grails plugin so grails doesn't support Neo4j and if we create our domain classes in domain package then it gives us an error.
So We create our domain in Services package. My First Question is:
We are right or we have to do another thing?
My another question is to provide the validation in this concept. We use the Command Object for it. So now we need some Custom validation for unique. I know we can use Validator for it, but we want that our logic only remain in Services. So can we create something like this?
static constraints = {
username size: 5..15
password size: 5..15, blank: false
userEmail email: true
}
username email:true
userName name:unique
I don't understand why you're so fixated on having to use a service for this. Creating a service annotated with #Validateable and using it as a non-GORM domain class seems very weird. If it works, cool, but it's sort of like driving to work in reverse the whole way. You'll get there (until you burn out the transmission) but it'll be a stressful drive looking in the rear view mirror and seeing everthing reversed the whole time.
Why not just put the classes in a sensible package under src/groovy and annotate those? You just need to register them in Config.groovy, e.g.
grails.validateable.classes = [
com.mycompany.myapp.User, com.mycompany.dto.Account]
You can do a uniqueness check, but not with the standard unique constraint. That's tied to GORM; it looks at the table or backing store for you domain class and runs a datastore-specific uniqueness query, but that doesn't apply here. But you can easily do the same thing yourself. Use a custom validator:
email validator: { value, obj ->
// run a Neo4j query checking to see if value has
// been used, the equivalent of
// "select count(email) from person where email=?"
// and return false if the count is not zero
}

how to serialize domain classes grails

I tried to serialize grails domains classes to Maps or similar in order to be able to store it in memcached.
I want to be able to read the objects only, I don't need gorm crud. Only to read them without breaking the kind of interfaces they have.
For instance: I could convert domains to maps, becouse it wouldn't break the interface for access like .<property> or .findall or similar
First I tried to do a manual serialization but it was very error prone. So I needed something more general.
Then I tried to serialize as a map with a grails codec.
Here is the testing repo.
Here is the snippet.
But I get StackOverFlowException.
I also tried to mark all the domains as Serializable but I need to reattach every domain when I bring them back from memcached to avoid hibernate errors like org.hibernate.LazyInitializationException: could not initialize proxy - no Session
Do you know a way to achieve this?
Is very frustrating to google search for something like this "storing domain classes in memcached" and find out is not a common problem.
I haven't see an out-of-the-box solution for doing this, but if you wanted to keep it generic you could do it manually (and consistently) like this:
def yourDomainInst = DefaultGrailsDomainClass(YourDomainClazz)
List listOfOnlyPersistantProperties = yourDomainInst.persistantProperties
def yourNewMap
yourObjects.each { obj ->
listOfOnlyPersistantProperties.each { prop ->
def propName = prop.name
yourNewMap.put(propName, obj."$propName")
}
}
Something like that should work. Note there's probably a hundred errors because I can't try it out right now, but that is the general idea.
Have a look at: Retrieving a list of GORM persistent properties for a domain

Resources