Hi,
I have a question about Hibernate Search stuff. I've tried to make this as short as I can, but it's hard! :
My basic requirement is to allow a free text search over a set of fields, but also adding addition filters to either add usefulness or enforce security requirements. i.e. at the front end there is a textbox for the users' search and a selectable date range.
I want to be able to search over my objects with the users query, and then filter/limit those results by the date range and my own requirements (i.e. something like: +isPublished:true).
So far, I have been testing this manually by building up a search query like this:
Code:
MultiFieldQueryParser parser = new MultiFieldQueryParser(new String[]{"modifiedDate", "memberName",
"agendaItemName", "agendaKeywords", "isPublished"}, new StandardAnalyzer());
String queryString = "+modifiedDate:["+bottomDateString+" TO "+ topDateString + "] +("+
"member.memberName:"+keywords+" "+
"agendaItems.agendaItemName:"+keywords+" "+
"agendaItems.agendaKeywords:"+keywords+" "+
") " +
"+isPublished:true";
Query luceneQuery = parser.parse(queryString);
org.hibernate.Query hibQuery = fullTextSession.createFullTextQuery(luceneQuery, Asset.class);
Although this works for simple cases, it's undeniably horrible and has a number of major show-stoppers in that it will fail completely if the user does a search like "+somesearchquery -someotherquery".
So, my question is - how do I do this programatically with Hibernate search. I notice in the "Lucene in Action" book some interesting bits:
Code:
Query query = MultiFieldQueryParser.parse("development", new String[]{"title", "subjects"}, new SimpleAnalyser());
Translating into my scenario, I have:
Code:
Query lucQ = MultiFieldQueryParser.parse(
new String[] {"isPublished:true","modifiedDate:["+bottomDateString+" TO "+ topDateString + "]",
keywords, keywords, keywords},
new String[] {"isPublished","modifiedDate", "member.memberName", "agendaItems.agendaItemName", "agendaItems.agendaKeywords"},
new BooleanClause.Occur[]{BooleanClause.Occur.MUST, BooleanClause.Occur.MUST, BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD},
new StandardAnalyzer());
Which is supposed to allow me to search over multiple fields. However, when I try this in Hibernate with a query like "-james", it generates me (correctly, I believe) the following:
Code:
+isPublished:true +modifiedDate:[20080223 TO 20080419] (-member.memberName:james) (-agendaItems.agendaItemName:james) (-agendItems.agendaKeywords:james)
The trouble with that is that the first two clauses in the query overpower the remaining clauses. In other words, I will still get results with 'james' in the fields because it is published and validates against a date.
What I need it to generate is:
Code:
+isPublished:true +modifiedDate:[20080223 TO 20080419] +((-member.memberName:james) (-agendaItems.agendaItemName:james) (-agendItems.agendaKeywords:james))
(notice extra "+(" )
I can't see any way of doing this short of parsing once (without my filtered bits) manually adding the "+(" and ")" and then appending my filtered stuff before parsing again and executing the query.
i.e.:
Code:
Query lucQ = MultiFieldQueryParser.parse(
new String[] {keywords, keywords, keywords},
new String[] {"member.memberName", "agendaItems.agendaItemName", "agendaItems.agendaKeywords"},
new StandardAnalyzer());
String genQry = lucQ.toString();
String newQry = "+isPublished:true +modifiedDate:[20080223 TO 20080419] +(" + genQry + ")";
Query luceneQuery = parser.parse(newQry);
org.hibernate.Query hibQuery = fullTextSession.createFullTextQuery(luceneQuery, Asset.class);
Am I missing something? While it seems to work, it still feels like a bit of a hack to me...
Many thanks for any help and thanks for reading.
James.