How to implement hierarchical facets

0. Environments

Ubuntu 14.x

Open JDK 7.x

Solr 3.6.x

Apache Tomcat 7.x

1. The problem

The solr documentation summaries approaches to implement hierarchical facets in: http://wiki.apache.org/solr/HierarchicalFaceting#Approaches_to_Hierarchical_Facets_in_Solr in different ways:

1) Use a prefix before the data to store hierarchy information, e.g.

1
2
3
Doc#1: 0/Fruit, 1/Apple, 2/Red
Doc#2: 0/Fruit, 1/Pear
Doc#3: 0/Fruit, 1/Apple, 2/Yellow

OR (even worse)

1
2
3
Doc#1: 0/Fruit, 1/Fruit/Apple, 2/Fruit/Apple/Red
Doc#2: 0/Fruit, 1/Fruit/Pear
Doc#3: 0/Fruit, 1/Fruit/Apple, 2/Fruit/Apple/Yellow

The problem of this approach is that we have to store extra data into solr and the hierarchy information is duplicated across solr.

2) “breadcrumbs”

1
2
3
Doc#1: Fruit > Apple > Red
Doc#2: Fruit > Pear
Doc#3: Fruit > Apple > Yellow

The above 2 suggested solutions all contain duplicated data, which is really bad. Actually, the hierarchy information should be stored separately to avoid duplication.

2. The solution

1) Store hierarchy information into an XML, e.g. a data dictionary:

1
2
3
4
5
6
7
8
9
<fruits>
<apple>
<red/>
<yellow/>
</apple>
<pear>
</pear>
......
<fruits>

2) Aggregate the hierarchy information with the actual solr data while retrieving data, e.g.

1
2
3
4
5
6
ITERATE ALL FACETS
GET DATA DICTIONARY FOR CURRENT FACET
ITERATE FACET ITEMS in CURRENT FACET
AGGREGATE DD WITH FACET ITEMS AND SAVE TO A HIERARCHICAL LIST
END
END

3) In the client code, based on the hierarchical list, constructing HTML elements, e.g, in JSP.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<c:forEach items="${availableFacets}" var="fc">
<ul class="XXXX">
<c:forEach items="${fc.iterator}" var="facetElement">
<li class="expanded">
<c:out value="${facetElement.label}"></c:out>[<c:out value="${facetElement.count}" />]</a>
</li>
<!-- Second level -->
<ul>
<c:forEach items="${facetElement.iterator}" var="secondLevelFacetElement">
<li class="expanded">
<c:out value="${secondLevelFacetElement.label}"></c:out>[<c:out value="${secondLevelFacetElement.count}" />]</a>
</li>
<!-- deeper levels -->
</c:forEach>
</ul>
</c:forEach>
</ul>
</c:forEach>

4) Based on the ul / li tags, render the hierarchical facets in Javascript, e.g. using jsTree (https://www.jstree.com/)

Share