31
2008
Using searchable across domain classes
Mike has done some great sleuthing on how to use Grails uber-cool searchable plugin to search a domain class based on properties of a nested class.
This is exactly what I’ve been looking for! Gravl supports multiple blogs per install, and when you are viewing my blog, I want those seaches to be constrained to fulltext search of just *my* blog, not all the data in the blog db.
My data model is 1:M from Blog to BlogEntry with a bidirectional link for navigation… So to make it all searchable I’ve got…
class Blog {
static hasMany = [ blogEntries : BlogEntry, tags : Tag, blogProperties : BlogProperty ]
static searchable = true
// ...
}
class BlogEntry {
static hasMany = [ comments : Comment, tags : Tag ]
static belongsTo = [ Blog ]
// we only index title and body, but index all fields in the parent "blog"
static searchable = {
title()
body()
blog(component: true)
}
Blog blog
//...
}
So by marking blog(component: true) we’re telling Compass to store Blogs fields in the index with the BlogEntry. Why do we want to do that? So we can search BlogEntry and impose criteria related to Blog. In my case, I want to do “find me all BlogEntry objects which contain the text ‘blah’ but limit the hits to those objects that have a blog.blogid of ‘glen’”. The code is simpler than the explanation! Here’s my whole search controller code which powers my search box:
def search = {
def query = params.query
def blogid = params.blog
def results = BlogEntry.search(query + " +blogid:${blogid}", params)
return [ results: results, query: query ]
}
And you’re got yourself blog-specific searching… Note that “blog.blogid” becomes just “blogid” in terms of field searching (ie. the component objects fields are collapsed into the parent).
Thanks Mike! Great pickup!
9 Comments + Add Comment
Leave a comment
Glen Smith
Archives
- January 2012
- November 2011
- October 2011
- September 2011
- August 2011
- July 2011
- June 2011
- April 2011
- March 2011
- January 2011
- November 2010
- October 2010
- September 2010
- August 2010
- July 2010
- June 2010
- May 2010
- April 2010
- February 2010
- January 2010
- December 2009
- November 2009
- October 2009
- September 2009
- August 2009
- July 2009
- June 2009
- May 2009
- April 2009
- March 2009
- December 2008
- November 2008
- October 2008
- September 2008
- August 2008
- July 2008
- June 2008
- May 2008
- April 2008
- March 2008
- February 2008
- January 2008
- December 2007
- November 2007
- October 2007
- September 2007
- August 2007
- July 2007
- June 2007
- May 2007
- April 2007
- March 2007
- February 2007
- January 2007
- December 2006
- November 2006
- October 2006
- September 2006
- August 2006
- July 2006
- June 2006
- May 2006
- April 2006
- March 2006
- February 2006
- January 2006
- December 2005
- November 2005
- October 2005
- September 2005
- August 2005
- July 2005
- June 2005
- May 2005
- April 2005
- March 2005
- February 2005
- January 2005
- December 2004
- November 2004
- October 2004
- September 2004
- August 2004
- July 2004
- June 2004
- May 2004
- March 2004
- February 2004
- January 2004
- December 2003
- November 2003
- October 2003
- September 2003

An article by Glen





How cool. I very much like the ‘searchable DSL’ !
Can you please describe how you made the searchable plugin work under RC4 and later? I did
grails create-app bookstore
grails install-plugin searchable
grails create-domain-class Book
added some properties and static searchable = true
grails generate-all Book
and
grails run-app
and get some weird error messages about URL controllers missing an action
which version of grails did you use to make it work?
Hi Chris.
I was using it under RC3, so I can’t speak for RC4.
The only issue I’ve had with it was a NullPointerException on startup for which you need a “patch”:http://jira.codehaus.org/browse/GRAILSPLUGINS-220 .
Other than that had no issues.
Hey Glen,
nice article
May I suggest writing the query with a builder closure like:
BlogEntry.search params, {
queryString(query)
must(term(“blogid”, blogid))
}
This way you separate the user query from your own internal query, so you can monkey with it, eg:
BlogEntry.search(params) {
queryString(query, [escape: true, defaultAndOperator: true])
must(term(“blogid”, blogid))
}
which escapes any dodgy characters and makes all terms in the query string required (this is just my example of course – it depends in your requirements as to how you treat user input!).
Second it allows you to bypass the query string parser for the blogid. Otherwise, if blogid was a word or words, and it’s put into the text query, it would be parsed and when Lucene actually does the query it might not be the query you intended, since it has stripped junk characters removed common words (and/or) etc!
I would typically map such properties as “un_tokenized”, meaning when they are saved to the index, they are not broken up into tokens (parsed) but instead are stored as complete verbatim text strings (preserving case and all). Then when you use “term” in the query builder, you can pass in the *exact* value you expect and your search will only match those exact values in the index.
See the Mapping section of the docs for how to achieve this.
As for the issues you and others have experienced here, I think there all fixed, but please raise issues if not
Awesome Maurice. Thanks for the tip. So good to have you back in the community!
Aw, thanks Glen :blush:
I’m enjoying reading your Gravl stories. It’s a great name too
Oh BTW I tried saving this comment without first entering my name and hit save and nothing happened. Then I looked in firebug and saw:
on
Mon, 3 Mar 2008 22:08
but I didn’t see the error displayed
Hi Glen,
I tried this example with two other domain classes which are
class Book {
Author author;
String name;
static searchable = {
name()
author(component: true)
}
static belongsTo = [Author];
}
class Author {
static searchable = true
String name;
String surname;
static hasMany = [books:Book]
}
and I performed following queries
Book.search(“authorid:1″);
Book.search(“authorname:Glen”);
both of these queries does not return anything.
am I doing any mistakes?
Thanks…
hi Glen
I want to use searchable in a many to many relationship
But I failed
Would you please tell me how to use that if you have any experiance about that
Thanks a lot
Hello,
I have book hasMany author and author belongsTo company
I want to search the books for the company x
Book.search {
…..
}
what i do ?