[hibernate-dev] [HSearch] Facet drilldown
Sanne Grinovero
sanne at hibernate.org
Mon Mar 14 11:24:13 EDT 2011
> As you guys know I've not been comfortable with the idea of reusing Filter as an implementation as it seem to be it is an implementation detail that we might change down the road and that is of no interest to the user.
I didn't understand you where exposing the filter, as I said in
previous mail I don't even sure it's the best way to implement it:
likely it is, but we should make sure we can switch approach so
definitely not in the public API.
>
> Instead of bitching abstractly, I've decided to implement a CDI style bean that implement faceted search to see how the API us used.
>
> Note that I have tried to implement what amazon does
> http://www.amazon.com/gp/search/ref=sr_nr_scat_392442011_ln?rh=n%3A392442011%2Ck%3Ascreen&keywords=screen&ie=UTF8&qid=1300105439&scn=392442011&h=9aa8a737035ed82d321ca117e8f48611956411e5#/ref=nb_sb_noss?url=node%3D392442011&field-keywords=screen&rh=n%3A172282%2Cn%3A%21493964%2Cn%3A281407%2Cn%3A172575%2Cn%3A392442011%2Ck%3Ascreen
>
> My feature list was:
> - multiple facets per query
> - ability to select one or more discrete facet values on a given facet (ie brand = epson or canon)
> - ability to display the facet menu on the left
> - ability to remember the state of the selected facet values
>
> While implementing it I've found several proposals for enhancement:
> - should we rename in thw facet DSL createFacet to createFacetRequest(), as it's the object returned
I'm +1 to match the return type, but is it really "XRequest", requests
sounds like we do some remote HTTP get. No strong opinion, as I can't
think of anything better.
> - does facet work with pagination (ie is not affected) => we did some optimization around QueryHits when paginating => add a unit test
Yes that's needed, especially as Lucene 3.1 changed the rules. I have
some fixes ready for that but I'm not sure how Faceting is expected to
interact with pagination, so you'd better hardcode your expectations
in a test before I send a pull request changing that all.
> - jpa.FullTextQuery does not have the facet methods
> - move Facet methods hosted on FTQuery to a FacetManager interface and do ftQuery.getFacetManager().enableFacet("cdscds");
> - make FacetRequest / FacetResults interfaces?
> - Facet should implement equals / hashCode or else we cannot remember the facet selected
> - //TODO should the index be included in object Facet? Not sure but worth thinking about => probably not if Facet objects change indexes from one query to the other
> - should we rename Facet to FacetElement? We seem to talk about Facets as the global concept whereas Facet the object represent one of the results of the Facet.
>
> The client of the service is as followed
> https://gist.github.com/869181
>
> The solution with the current API is as followed
> https://gist.github.com/869143
>
> In this implementation:
> - I need to keep some kind of state besides the query to remember which facet has been selected by the user and which one have not been.
> - I need to remember this state across query re execution: even if the request (and thus the facetREsults) are updated, I need to remember this state or the user will yell
> - FacetFilter as it is does not solve the problem at had as I need to:
> . use a OR filter for selected elements across a Facet
> . use AndFilter to aggregate the various facets and filter the results across all of them
> - I ended up writing and manipulating various OrFacetFilter and AndFilter object which are not exactly easy to play with
>
> I've worked on an alternative API that internalize the management of this facet element selection so that the whole filter tree can be managed by Hibernate Search itself and exposed to the user as a service
>
> https://gist.github.com/869145
>
> Query execution and faceting display are of similar complexity. But the select or deselect method is simpler. Also note that I no longer need to implement or manipulate And/Or filters myself (and potentially forget to set it).
> I have attached the state of the selected facet elements on the FacetRequest (the FacetResults are destroyed and reset upon requery). We might want to move it up to FacetManager (not shown here), I ahve not thought about it.
Yes, it looks great. It always takes a user to polish an API.
> What do you guys think? If I had to write a book on Hibernate Search, I'd prefer the second option by a big margin.
Are you having plans? I'd say the second options is better even
without needing to write a book.
Sanne
>
> On 11 mars 2011, at 20:08, Hardy Ferentschik wrote:
>
>> Hi,
>>
>> sorry for the following lengthy code example, but it is hard to
>> demonstrate this much shorter.
>> The example shows how you can enable multiple facets and then continuously
>> restrict the query result
>> by chaining facets into a FacetFilter (which delegates to a ChainedFilter
>> underneath). WDYT?
>> If you want to see all the code or even get the feature branch -
>> https://github.com/hferentschik/hibernate-search/blob/HSEARCH-706
>>
>>
>> public void testMultipleFacetDrillDown() throws Exception {
>> final String ccsFacetName = "ccs";
>> final String ccsFacetFieldName = "cubicCapacity";
>> FacetRequest ccsFacetRequest = queryBuilder( Car.class ).facet()
>> .name( ccsFacetName )
>> .onField( ccsFacetFieldName )
>> .discrete()
>> .createFacet();
>>
>> final String colorFacetName = "color";
>> final String colorFacetFieldName = "color";
>> FacetRequest colorFacetRequest = queryBuilder( Car.class ).facet()
>> .name( colorFacetName )
>> .onField( colorFacetFieldName )
>> .discrete()
>> .createFacet();
>>
>> FullTextQuery query = createMatchAllQuery( Car.class );
>> query.enableFacet( colorFacetRequest );
>> query.enableFacet( ccsFacetRequest );
>> assertEquals( "Wrong number of query matches", 50, query.getResultSize()
>> );
>>
>> List<Facet> colorFacetList = getFacetListForFacet( query, colorFacetName
>> );
>> assertFacetCounts( colorFacetList, new int[] { 12, 12, 12, 12, 2 } );
>>
>> List<Facet> ccsFacetList = getFacetListForFacet( query, ccsFacetName );
>> assertFacetCounts( ccsFacetList, new int[] { 17, 16, 16, 1 } );
>>
>> FacetFilter facetFilter = new FacetFilter();
>> query.setFilter( facetFilter );
>>
>> facetFilter.addFacet( colorFacetList.get( 0 ) );
>> colorFacetList = getFacetListForFacet( query, colorFacetName );
>> assertFacetCounts( colorFacetList, new int[] { 12, 0, 0, 0, 0 } );
>>
>> ccsFacetList = getFacetListForFacet( query, ccsFacetName );
>> assertFacetCounts( ccsFacetList, new int[] { 4, 4, 4, 0 } );
>>
>> facetFilter.addFacet( ccsFacetList.get( 0 ) );
>> // needs to set the filter explicitly atm, because I need the query
>> state to reset
>> query.setFilter( facetFilter );
>> colorFacetList = getFacetListForFacet( query, colorFacetName );
>> assertFacetCounts( colorFacetList, new int[] { 4, 0, 0, 0, 0 } );
>>
>> ccsFacetList = getFacetListForFacet( query, ccsFacetName );
>> assertFacetCounts( ccsFacetList, new int[] { 4, 0, 0, 0 } );
>> }
>>
>> I like the idea of using Lucene Filters to implement the drilldown for. It
>> seems the most natural and the original query stays
>> untouched.
>>
>> --Hardy
>>
>> _______________________________________________
>> hibernate-dev mailing list
>> hibernate-dev at lists.jboss.org
>> https://lists.jboss.org/mailman/listinfo/hibernate-dev
>
>
> _______________________________________________
> hibernate-dev mailing list
> hibernate-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/hibernate-dev
>
More information about the hibernate-dev
mailing list