Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion autocompleter/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION = (1, 1, 2)
VERSION = (1, 1, 3)


from autocompleter.registry import registry, signal_registry
Expand Down
94 changes: 46 additions & 48 deletions autocompleter/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -706,14 +706,6 @@ def suggest(self, term, facets=[]):
facet_final_exact_match_key,
}

facet_keys_set = set()
if len(facets) > 0:
# we use from_iterable to flatten the list comprehension into a single list
sub_facets = itertools.chain.from_iterable(
[facet["facets"] for facet in facets]
)
facet_keys_set = set([sub_facet["key"] for sub_facet in sub_facets])

MOVE_EXACT_MATCHES_TO_TOP = registry.get_autocompleter_setting(
self.name, "MOVE_EXACT_MATCHES_TO_TOP"
)
Expand Down Expand Up @@ -757,46 +749,54 @@ def suggest(self, term, facets=[]):
final_result_key = base_result_key
pipe.zunionstore(final_result_key, term_result_keys, aggregate="MIN")

use_facets = False
if len(facet_keys_set) > 0:
provider_keys_set = set(provider.get_facets())
if facet_keys_set.issubset(provider_keys_set):
use_facets = True

if use_facets:
facet_result_keys = []
for facet in facets:
try:
facet_type = facet["type"]
if facet_type not in ["and", "or"]:
continue
facet_list = facet["facets"]
facet_set_keys = []
for facet_dict in facet_list:
facet_set_key = FACET_SET_BASE_NAME % (
provider_name,
facet_dict["key"],
facet_dict["value"],
)
facet_set_keys.append(facet_set_key)
provider_keys_set = set(provider.get_facets())

if len(facet_set_keys) == 1:
facet_result_keys.append(facet_set_keys[0])
else:
facet_result_key = RESULT_SET_BASE_NAME % str(uuid.uuid4())
facet_result_keys.append(facet_result_key)
keys_to_delete.add(facet_result_key)
if facet_type == "and":
pipe.zinterstore(
facet_result_key, facet_set_keys, aggregate="MIN"
)
else:
pipe.zunionstore(
facet_result_key, facet_set_keys, aggregate="MIN"
)
except KeyError:
facets_used = False
facet_result_keys = []
for facet_group in facets:
try:
facet_type = facet_group["type"]
if facet_type not in ["and", "or"]:
continue

facet_list = facet_group["facets"]
facet_group_keys_set = set([sub_facet["key"] for sub_facet in facet_list])
if not facet_group_keys_set.issubset(provider_keys_set):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirming my understanding: so we are keeping the subset logic check but instead of checking all facets passed in is a subset of the provider's facets, we now check each facet group passed in is a subset of the provider facets. So we need to make sure we pass in new facet groups if we want them to work with providers that have unique facets

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah exactly, each 'and' or 'or' facet group will be treated independently of each other; for each facet group we'll check to see if it's a subset of provider facets to see whether we can evaluate and use that particular facet group.

# For a given facet_group, if the provider does not support all the facet keys, then we can't
# filter based on it, and we skip the facet_group
continue

facet_set_keys = []
for facet_dict in facet_list:
facet_set_key = FACET_SET_BASE_NAME % (
provider_name,
facet_dict["key"],
facet_dict["value"],
)
facet_set_keys.append(facet_set_key)

if len(facet_set_keys) == 0:
continue
elif len(facet_set_keys) == 1:
facet_result_keys.append(facet_set_keys[0])
else:
facet_result_key = RESULT_SET_BASE_NAME % str(uuid.uuid4())
facet_result_keys.append(facet_result_key)
keys_to_delete.add(facet_result_key)
if facet_type == "and":
pipe.zinterstore(
facet_result_key, facet_set_keys, aggregate="MIN"
)
else:
pipe.zunionstore(
facet_result_key, facet_set_keys, aggregate="MIN"
)
except KeyError:
continue

facets_used = True

if facets_used:
# We want to calculate the intersection of all the intermediate facet sets created so far
# along with the final result set. So we append the final_result_key to the list of
# facet_result_keys and store the intersection in the faceted final result set.
Expand All @@ -805,8 +805,6 @@ def suggest(self, term, facets=[]):
facet_result_keys + [final_result_key],
aggregate="MIN",
)

if use_facets:
pipe.zrange(facet_final_result_key, 0, MAX_RESULTS - 1)
else:
pipe.zrange(final_result_key, 0, MAX_RESULTS - 1)
Expand Down Expand Up @@ -836,7 +834,7 @@ def suggest(self, term, facets=[]):
# exact term matches don't bypass the requirement of having matching facet values.
# To achieve this, we intersect all faceted matches (exact-and-non-exact) with
# all exact matches.
if use_facets:
if facets_used:
pipe.zinterstore(
facet_final_exact_match_key,
facet_result_keys + [final_exact_match_key],
Expand Down
42 changes: 42 additions & 0 deletions test_project/test_app/tests/test_matching.py
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,48 @@ def test_multiple_facet_dicts_match(self):
matches = self.autocomp.suggest("ch", facets=facets)
self.assertEqual(len(matches), 2)

def test_multiple_facet_dicts_match_subset(self):
"""
Matching with multiple passed in facet dicts works
"""
facets = [
{
"type": "and",
"facets": [{"key": "sector", "value": "Communication Services"}],
},
{
"type": "and",
"facets": [{"key": "industry", "value": "Telecom Services"}],
},
]
extra_facet = {
"type": "or",
"facets": [{"key": "fake_key", "value": "fake value"}, {"key": "sector", "value": "Energy"}],
}
all_facets = facets + [extra_facet]

regular_matches = self.autocomp.suggest("ch", facets=facets)
matches = self.autocomp.suggest("ch", facets=all_facets)
self.assertEqual(len(matches), 1)
self.assertEqual(regular_matches, matches)

facets = [
{"type": "and", "facets": [{"key": "sector", "value": "Energy"}]},
{
"type": "and",
"facets": [{"key": "industry", "value": "Oil & Gas Integrated"}],
},
]
extra_facet = {
"type": "or",
"facets": [{"key": "fake_key", "value": "fake value"}, {"key": "sector", "value": "Communication Services"}],
}
all_facets = facets + [extra_facet]
regular_matches = self.autocomp.suggest("ch", facets=facets)
matches = self.autocomp.suggest("ch", facets=all_facets)
self.assertEqual(len(matches), 2)
self.assertEqual(regular_matches, matches)


class MixedFacetProvidersMatchingTestCase(AutocompleterTestCase):
fixtures = ["stock_test_data_small.json", "indicator_test_data_small.json"]
Expand Down
Loading