Skip to content
This repository has been archived by the owner on Jul 11, 2023. It is now read-only.

Commit

Permalink
fix(facetValues): retrieve all hierarchical facet parent values (#908)
Browse files Browse the repository at this point in the history
  • Loading branch information
dhayab authored Jun 15, 2022
1 parent 64356a4 commit 420111b
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 49 deletions.
78 changes: 40 additions & 38 deletions src/SearchResults/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ function SearchResults(state, results, options) {
nextDisjunctiveResult++;
});

// if we have some root level values for hierarchical facets, merge them
// if we have some parent level values for hierarchical facets, merge them
state.getRefinedHierarchicalFacets().forEach(function(refinedFacet) {
var hierarchicalFacet = state.getHierarchicalFacetByName(refinedFacet);
var separator = state._getHierarchicalFacetSeparator(hierarchicalFacet);
Expand All @@ -533,47 +533,49 @@ function SearchResults(state, results, options) {
return;
}

var result = results[nextDisjunctiveResult];
var facets = result && result.facets
? result.facets
: {};
Object.keys(facets).forEach(function(dfacet) {
var facetResults = facets[dfacet];
var position = findIndex(state.hierarchicalFacets, function(f) {
return f.name === hierarchicalFacet.name;
});
var attributeIndex = findIndex(self.hierarchicalFacets[position], function(f) {
return f.attribute === dfacet;
});
results.slice(nextDisjunctiveResult).forEach(function(result) {
var facets = result && result.facets
? result.facets
: {};

// previous refinements and no results so not able to find it
if (attributeIndex === -1) {
return;
}
Object.keys(facets).forEach(function(dfacet) {
var facetResults = facets[dfacet];
var position = findIndex(state.hierarchicalFacets, function(f) {
return f.name === hierarchicalFacet.name;
});
var attributeIndex = findIndex(self.hierarchicalFacets[position], function(f) {
return f.attribute === dfacet;
});

// when we always get root levels, if the hits refinement is `beers > IPA` (count: 5),
// then the disjunctive values will be `beers` (count: 100),
// but we do not want to display
// | beers (100)
// > IPA (5)
// We want
// | beers (5)
// > IPA (5)
var defaultData = {};

if (currentRefinement.length > 0) {
var root = currentRefinement[0].split(separator)[0];
defaultData[root] = self.hierarchicalFacets[position][attributeIndex].data[root];
}
// previous refinements and no results so not able to find it
if (attributeIndex === -1) {
return;
}

self.hierarchicalFacets[position][attributeIndex].data = defaultsPure(
defaultData,
facetResults,
self.hierarchicalFacets[position][attributeIndex].data
);
});
// when we always get root levels, if the hits refinement is `beers > IPA` (count: 5),
// then the disjunctive values will be `beers` (count: 100),
// but we do not want to display
// | beers (100)
// > IPA (5)
// We want
// | beers (5)
// > IPA (5)
var defaultData = {};

if (currentRefinement.length > 0) {
var root = currentRefinement[0].split(separator)[0];
defaultData[root] = self.hierarchicalFacets[position][attributeIndex].data[root];
}

nextDisjunctiveResult++;
self.hierarchicalFacets[position][attributeIndex].data = defaultsPure(
defaultData,
facetResults,
self.hierarchicalFacets[position][attributeIndex].data
);
});

nextDisjunctiveResult++;
});
});

// add the excludes
Expand Down
34 changes: 27 additions & 7 deletions src/requestBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,38 @@ var requestBuilder = {
});
});

// maybe more to get the root level of hierarchical facets when activated
// More to get the parent levels of the hierarchical facets when refined
state.getRefinedHierarchicalFacets().forEach(function(refinedFacet) {
var hierarchicalFacet = state.getHierarchicalFacetByName(refinedFacet);

var currentRefinement = state.getHierarchicalRefinement(refinedFacet);
// if we are deeper than level 0 (starting from `beer > IPA`)
// we want to get the root values
var separator = state._getHierarchicalFacetSeparator(hierarchicalFacet);

// If we are deeper than level 0 (starting from `beer > IPA`)
// we want to get all parent values
if (currentRefinement.length > 0 && currentRefinement[0].split(separator).length > 1) {
queries.push({
indexName: index,
params: requestBuilder._getDisjunctiveFacetSearchParams(state, refinedFacet, true)
// We generate a map of the filters we will use for our facet values queries
var filtersMap = currentRefinement[0].split(separator).slice(0, -1).reduce(
function createFiltersMap(map, segment, level) {
return map.concat({
attribute: hierarchicalFacet.attributes[level],
value: level === 0
? segment
: [map[map.length - 1].value, segment].join(separator)
});
}
, []);

filtersMap.forEach(function(filter, level) {
var params = requestBuilder._getDisjunctiveFacetSearchParams(
state,
filter.attribute,
level === 0
);

var parent = filtersMap[level - 1];
params.facetFilters = level > 0 ? [parent.attribute + ':' + parent.value] : undefined;

queries.push({indexName: index, params: params});
});
}
});
Expand Down
48 changes: 44 additions & 4 deletions test/spec/hierarchical-facets/simple-usage.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,21 @@ test('hierarchical facets: simple usage', function(done) {
'facets': {
'categories.lvl0': {'beers': 20, 'fruits': 5, 'sales': 20}
}
}, {
'query': 'a',
'index': indexName,
'hits': [{'objectID': 'one'}],
'nbHits': 1,
'page': 0,
'nbPages': 1,
'hitsPerPage': 1,
'facets': {
'categories.lvl1': {
'beers > IPA': 9,
'beers > Pale Ale': 10,
'beers > Stout': 1
}
}
}]
};

Expand Down Expand Up @@ -104,6 +119,22 @@ test('hierarchical facets: simple usage', function(done) {
'exhaustive': true,
'data': null
}]
}, {
'name': 'Pale Ale',
'path': 'beers > Pale Ale',
'escapedValue': 'beers > Pale Ale',
'count': 10,
'isRefined': false,
'exhaustive': true,
'data': null
}, {
'name': 'Stout',
'path': 'beers > Stout',
'escapedValue': 'beers > Stout',
'count': 1,
'isRefined': false,
'exhaustive': true,
'data': null
}]
}, {
'name': 'fruits',
Expand Down Expand Up @@ -134,17 +165,26 @@ test('hierarchical facets: simple usage', function(done) {
var queries = client.search.mock.calls[0][0];
var hitsQuery = queries[0];
var parentValuesQuery = queries[1];
var rootValuesQuery = queries[2];
var fullParentsValuesQueries = queries.slice(2);

expect(queries.length).toBe(4);

expect(queries.length).toBe(3);
expect(hitsQuery.params.facets).toEqual(
['categories.lvl0', 'categories.lvl1', 'categories.lvl2', 'categories.lvl3']
);
expect(hitsQuery.params.facetFilters).toEqual([['categories.lvl2:beers > IPA > Flying dog']]);

expect(parentValuesQuery.params.facets).toEqual(['categories.lvl0', 'categories.lvl1', 'categories.lvl2']);
expect(parentValuesQuery.params.facetFilters).toEqual([['categories.lvl1:beers > IPA']]);
expect(rootValuesQuery.params.facets).toEqual(['categories.lvl0']);
expect(rootValuesQuery.params.facetFilters).toBe(undefined);

// Root
expect(fullParentsValuesQueries[0].params.facets).toEqual('categories.lvl0');
expect(fullParentsValuesQueries[0].params.facetFilters).toBe(undefined);

// Level 1
expect(fullParentsValuesQueries[1].params.facets).toEqual('categories.lvl1');
expect(fullParentsValuesQueries[1].params.facetFilters).toEqual(['categories.lvl0:beers']);

expect(event.results.hierarchicalFacets).toEqual(expectedHelperResponse);
expect(event.results.getFacetByName('categories')).toEqual(expectedHelperResponse[0]);

Expand Down
24 changes: 24 additions & 0 deletions test/spec/requestBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,30 @@ test('does only a single query if refinements are empty', function() {
expect(queries).toHaveLength(1);
});

test('does multiple queries to retrieve all facet values of hierarchical parent levels', function() {
var searchParams = new SearchParameters({
hierarchicalFacets: [{
name: 'categories.lvl0',
attributes: ['categories.lvl0', 'categories.lvl1', 'categories.lvl2']
}],
hierarchicalFacetsRefinements: {
'categories.lvl0': ['beers > IPA > Flying dog']
}
});

var queries = getQueries(searchParams.index, searchParams);

expect(queries).toHaveLength(4);

// Root
expect(queries[2].params.facets).toEqual(['categories.lvl0']);
expect(queries[2].params.facetsFilters).toBeUndefined();

// Level 1
expect(queries[3].params.facets).toEqual('categories.lvl1');
expect(queries[3].params.facetFilters).toEqual(['categories.lvl0:beers']);
});

describe('wildcard facets', function() {
test('keeps as-is if no * present', function() {
var searchParams = new SearchParameters({
Expand Down

0 comments on commit 420111b

Please sign in to comment.