Grails Elasticsearch plugin issues - grails

I am new to Elasticsearch and am using the revived grails plugin "elasticsearch:0.0.4.6".
I wanted to implement a search for a User by their firstName, surname or username, which returns the full domain instance.
I have a 2 domain classes:
User:
class User {
String firstName
String surname
static hasOne = [profile:Profile]
static hasMany = [friends:User]
static mappedBy = [ friends: 'friends' ]
static searchable = {
profile component:true
only = ['firstName', 'surname', 'profile']
}
...
Profile:
class Profile {
String username
String status
byte[] photo
static belongsTo = [user:User]
static searchable = true
...
}
I made the classes "searchable = true" and then created the following search:
def res = User.search("${params.friendSearch}").searchResults
This found the correct instances, but now when a user adds a photo to their profile, it suceeds but I recieve a never ending loop of the following error:
ERROR index.IndexRequestQueue - Failed bulk item: MapperParsingException[failed to parse [photo]]; nested: NumberFor
matException[For input string: the photos base64inputstring
I dont really get what is happening, but i figure it must be something to do with elasticsearch being unable to index the photo data. Can somebody provide an explanation?
I then experimented with searchables custom mapping options -
profile index:'no'
all=false
excludeFromAll = true
etc
Nothing worked. Eventually I added
only = ['username']
and it stopped the error from occuring and allowed me to find users based on the criteria i mentioned above. However, because of the "only" limit, it means that the User instances returned by the seach have a photo property equal to null, but i need this value!
What am i doing wrong? Can anyone advise me on the best course of action to take or any misunderstandings i have about Elasticsearch? Thanks

I think you might have to exclude the byte property photo from the searchable fields like so:
class Profile {
String username
String status
byte[] photo
static belongsTo = [user:User]
static searchable = {
except = ['photo']
}
This will exclude the property photo from being indexed and search. Hence the output of converting the byte format to string format will not fail.
Also maybe you might need a custom convertor to change the byte(string) to something more usable in the results?

Related

Grails findBy is not working with combination of Or/And Condition

I am working with Grails application. I am using Apache Shiro security plugin for my grails application. I am trying to use findBy query on my User domain class with Or and And condition but it gives me an error.
My Domain Class
class ShiroUser {
String firstName
String lastName
String username
String email
String passwordHash
String userStatus
static hasMany = [ roles: ShiroRole, permissions: String ]
static constraints = {
username(nullable: false, blank: false, unique: true)
email(nullable: false, blank: false, email: true,unique: true)
}}
I have executed following query:
ShiroUser.findByUsernameOrEmailAndUserStatus(params?.username,params?.username,'Active')
I get following error:
Message: No property found for name [usernameOrEmail] for class [class com.chatportal.ShiroUser]
But If I execute query with only Or condition then it works fine.
ShiroUser.findByUsernameOrEmail(params?.username,params?.username)
Anyone please help me that what is wrong with my condition when I used Or and And condition with findBy ?
"You can combine as many criteria as you like, but they must all be combined with And or all Or. If you need to combine And and Or or if the number of criteria creates a very long method name, just convert the query to a Criteria or HQL query."

Grails find by property

Okay, I am trying to find all of my Employee that have a given role... However no matter what I try I end up getting the same exception thrown...
enum Role {
SFC("State Fitness Coordinator"),
TRAINING("Training"),
DFC("District Fitness Coordinator"),
final String longName
private Role(String longName) {
this.longName = longName
}
}
class Employee {
static hasMany = [roles: Role]
static constraints = {
}
}
The first Thing I tried was Employee.findAllByRoles(Role.DFC)
Then I tried:
Employee.findAll("FROM Employee e WHERE e.roles IN (:role)", [role: [Role.DFC]])
as well as
Employee.withCriteria {
'in'('roles', [Role.DFC])
}
all resulting in
Class
java.sql.SQLException
Message
Missing IN or OUT parameter at index:: 1
Any direction would be much appreciated.
with grails 2.3.8 and H2
Employee.findAll("FROM Employee e WHERE :role in elements(e.roles) ", [role: Role.DFC.toString()])
this works… even if I think that Role could be a real Domain simplifying all operations
I think the problem is that Role is an enum. Are you sure you want to make it an enum?
I recommend making it a class since new roles might be added. If so, you can easily add a record using bootstrap or SQL query without making a new build to production.
class Role {
String roleName
String description
}
In Bootstrap:
Role sfc = new Role("SFC","State Fitness Coordinator")
Role sfc = new Role("TRAINING," "Training")
Role sfc = new Role("DFC", "District Fitness Coordinator")
N.B. Please make sure you are not using spring security plugin which has its own 'Role' class. If so, please change the name of your 'Role' class to something like 'EmployeeRole'

Grails loading data once

I have these 2 domains
class Country {
String name
static hasMany = [cities:City]
}
class City {
String name;
static belongsTo = [country: Country]
}
The data contained in these 2 tables is relatively big, and they're used in all the screens,
every time i choose a country i have to reload all its cities.
How can I load the data only once in memory so i can access it faster in all the screens.
I tried putting cities for eager fetching, and tried using cache plugin.
Thank you
You can configure both domain classes to be cached automatically and also cache the cities relation in Country:
class Country {
String name
static hasMany = [cities:City]
static mapping = {
cache true
cities cache:true
}
}
class City {
String name
static belongsTo = [country: Country]
static mapping = {
cache true
}
}
Caching is often a good strategy, but remember that caches have expiry parameters so if left idle your app may reload from the DB again. Depending on your cache provider you'll have to tune this, eg For ehcache edit your ehcache.xml in the grails config folder and set (cache name is the same as your Domain class including package name):
<cache name="Country" maxElementsInMemory="1000" timeToIdleSeconds="0" timeToLiveSeconds="0"/>
You should also move the query into a service, the service is by default singleton scoped and the service method also cachable.
An alternative is to store them in application scope such as in your Bootstrap.groovy run the query and assign the results:
servletContext.countries = Country.list()
Retrieve them in the same way, eg
in a controller:
List<Country> countries = servletContext.countries
or gsp:
<g:each var="country" in="${application.countries}">
${country}
</g:each>
If you have eager fetching on then you should see no DB hits.

Custom type converter doesn't appear to work in Filter

I am using the GSON type converter in a filter as follows...
def account = new Object(){
String firstName, lastName
};
if(springSecurityService.isLoggedIn()){
account.setFirstName(springSecurityService.principal.givenName);
account.setLastName(springSecurityService.principal.familyName);
}
String test = account as GSON;
But test is always null, even thought the object is populated properly. I don't like all the extra data in the normal JSON serializer. So does anyone know why this does not work?
UPDATE
I get the following when converting to JSON...
Caused by: java.lang.IllegalAccessException: Class org.codehaus.groovy.grails.web.converters.marshaller.json.GenericJavaBeanMarshaller can not access a member of class org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor with modifiers "public"

Unable to create new domain object in Grails

Hi there i am still very new to grails and I have not been able to figure out why this is happening.
I have a domain class:
package scheduler
class Client {
String name
static constraints = {}
}
And a controller:
package scheduler
class AdminController {
def create() {
def client = new Client(name:"John")
println client
}
}
Currently I am always getting null for client. Originally the above was a little more complex on the domain class side but I systematically dumbed it down to see if it was a problem there. I still can not get the above working.
The output is always
scheduler.Client : null
Please let me know if I need to provide anymore information.
It's not null, that's just the default output of the toString method that Grails adds. It prints the class name and the id. Since you haven't saved the instance, the id is null. If the instance was null the output would have been null, not scheduler.Client : null
If you want to see the data in the instance, use the Groovy dump() method, e.g.
def client = new Client(name:"John")
println client.dump()
You could also add a toString method that includes the name attribute, e.g.
package scheduler
class Client {
String name
String toString() { name }
}

Resources