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.

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
 - does facet work with pagination (ie is not affected) => we did some 
optimization around QueryHits when paginating => add a unit test
 - 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.

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.

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@lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/hibernate-dev


_______________________________________________
hibernate-dev mailing list
hibernate-dev@lists.jboss.org
https://lists.jboss.org/mailman/listinfo/hibernate-dev

Reply via email to