How to build Faceted Navigation without pain with Elastica?

1,571 views
Skip to first unread message

dalex...@jolicode.com

unread,
Apr 12, 2013, 1:12:42 PM4/12/13
to elastica-...@googlegroups.com
Hi everyone, 

I'm building a faceted navigation with Elastica, and it's not easy - maybe I'm doing it wrong?

Let's say I have documents like this:

{
  title: "Hi there",
  text: "Lipsum",
  author: "Damien"
}

{
  title: "Hi there 2",
  text: "Lipsum 2",
  author: "Damien"
}

{
  title: "Hi there 3",
  text: "Lipsum 3",
  author: "Robert"
}

I have this search:

    $elasticaQueryString = new Elastica\Query\QueryString("Hi");
    $elasticaQuery = new Elastica\Query();
    $elasticaQuery->setQuery($elasticaQueryString);

    $facets = array();
    $elasticaFacet = new \Elastica\Facet\Terms('author');
    $elasticaFacet->setField('author');
    $elasticaFacet->setSize(10);
    $facets[] = $elasticaFacet;

    // More facets here...

    $elasticaQuery->setFacets($facets);

    $search = new \Elastica\Search($this->getClient());
    $search->setQuery($elasticaQuery);

The result is fine. And I get a Facet "author" with two terms, Damien (2) and Robert (1).

Now, what's happen if my user select the Facet "author" of value "Damien"? I want to apply this facet value to my request,
but there is no way to do it?

Seem's to me that there is no way to actually set as "selected value" to a Facet?

How I do it is quite painful:

    // Depending on my query string, I retrieve the facet:
    $filter = new \Elastica\Filter\Terms($facet->getParam('field'), array($term));

and then I transform my Query to a Filtered Query:

    $elasticaQuery->setQuery(new Elastica\Query\Filtered($elasticaQueryString, $filter));

This only works for Term facets, and I don't want to map the Facets types to Query types manually! 

Does Elastica could do that?
How do you apply a selected Facet to a query? 

I dont't understand this test here: https://github.com/ruflin/Elastica/blob/master/test/lib/Elastica/Test/Facet/FilterTest.php, I think this is not what I need.

This is a lot of questions,
I hope I have explained it well :)

Also, it's for a Symfony project, I'm quite sure this kind of feature is a must have for search,
I'm very surprised to find so low resources about Faceted navigation for ElasticSearch...

Have a nice weekend!
Damien

ruflin

unread,
Apr 15, 2013, 9:55:35 AM4/15/13
to elastica-...@googlegroups.com
Hi Damien

I will check your question later in detail. A short question for you until then: Did you find some ways to implement this in the elasticsearch documentation directly? http://www.elasticsearch.org/guide/reference/api/search/facets/

So is this more a question related to elasticsearch or Elastica itself?

Nicolas

Damien Alexandre

unread,
Apr 15, 2013, 10:06:11 AM4/15/13
to elastica-...@googlegroups.com
Hi Ruflin,

yes I already have Faceted searches that works,

Here is a quick gist of how I am doing it (it's Json but I'm using Elastica): https://gist.github.com/damienalexandre/5386906

What I miss, is a way of telling: "Hey, my facet "color" has been selected, filter all the search on the "red" value !".
This will not come from ES, so I think we can do it in Elastica.

When I have a "term" facet selected by a user,
I do not want to have to create manually my \Elastica\Filter\Terms().
Yes I'm lazy :)

I already have a small algo to build the new Query for me, but it's kind of crappy atm,
that's why I'm looking for help or advices.

How do you, ES users, implement faceted navigation on your websites? How can Elastica help with that? 
There is plenty of examples telling you how to ask for facets, none of them tell you how to apply a selected facet.

Maybe there is room for a contrib to Elastica here, 
but I'm not a facet expert, all inputs are welcome!

Cheers,
Damien



--
You received this message because you are subscribed to a topic in the Google Groups "Elastica - Elasticsearch PHP Client" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elastica-php-client/zFgVvildmVM/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to elastica-php-cl...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

ruflin

unread,
Apr 16, 2013, 4:28:08 AM4/16/13
to elastica-...@googlegroups.com
Hi Damien

I understand what you are aiming at. The question for is how the workflow actually is. Because I see your point, that after having facets, most of the time after that you need a specific Term(s) query/filter. But in the implementations I know, it is a different controller (as it is a different page/module) that shows the new data, which means also the queries are recreated. So I would be curious how your implementation is.

As a side note: I'm quite often a little bit skeptical of implementing Application specific stuff in Elastica as I think it is important to keep Elastica as simple as possible. If there is application specific stuff, normally an extension to Elastica makes sense. Also as you are using the Symfony extension, perhaps it makes more sense directly in the Symfony extension. But this doesn't mean you cannot convince me to get it directly into Elastica ;-)

Nicolas

ibasaw

unread,
May 28, 2013, 4:05:55 AM5/28/13
to elastica-...@googlegroups.com
Hi Damien,

Can you please share with us your code php about facet ?

it will be very helful for me

i try to do it with elasticsearch php + FOSElasticaBundle for SF2

thanks,
bye

Damien Alexandre

unread,
May 28, 2013, 4:35:36 AM5/28/13
to elastica-...@googlegroups.com
Hi,

Actually I do not think my code is ready to use by everyone but it works for me... So here it is.
Also note that I do not use ElasticaBundle.

I have a method building a list of Facets of different types:

        $elasticaFacet = new \Elastica\Facet\Terms('label');
        $elasticaFacet->setField('label.name.untouched');
        $elasticaFacet->setSize($size);
        $facets[] = $elasticaFacet; 


        $elasticaFacet = new \Elastica\Facet\Range('released_at');
        $elasticaFacet->setField('released_at');
        $elasticaFacet->setRanges(array(
          array('from' => $today_timestamp),
          array('from' => $today_timestamp - $one_month,          'to' => $today_timestamp),
          array('from' => $today_timestamp - ($one_month * 3),    'to' => $today_timestamp),
          array('from' => $today_timestamp - ($one_month * 12),   'to' => $today_timestamp),
        ));
        $facets[] = $elasticaFacet;


        $elasticaFacet = new \Elastica\Facet\Filter('price_promo');
        $elasticaFacet->setFilter(
          new \Elastica\Filter\Exists('articles.promotion.id')
        );
        $facets[] = $elasticaFacet;

I inject them in my Search and then I display them in my UI - that's the easy part.
When a user select a facet, it append a query string, like &released_at=2 (range facets use numeric key of the selected range) or &label=Toto.

What my question was about is how to apply the selected Facets without pain. So I build a little method to help me transform my facet query string to actuel Filter,
to apply on a FilteredQuery.

The code only handle 3 facet types and is not bulletproof, it fit in my case, maybe not yours ;-)

Feel free to complete, improve and comment this code, it can certainly be improved (for example, if the Elastica\Facet\Filter could provide a method to get the original Filter object back, I could avoid doing a $facet->toArray()).

Have a nice day,
Cheers!


ibasaw

unread,
May 28, 2013, 4:54:29 AM5/28/13
to elastica-...@googlegroups.com
@Damien,  thank you very much, i will try with this ;)
Message has been deleted

ibasaw

unread,
May 30, 2013, 7:44:26 AM5/30/13
to elastica-...@googlegroups.com
ok, i succeeded to use facet.

Now i need the exact same thing as you.

Apply a filter on data and Facet, when a user click on a facet value.

I will check your code more in detail...and really appreicate other solutions too...is ther a way more easy to do that ?
Reply all
Reply to author
Forward
0 new messages