Skip to content

Commit 9f277a0

Browse files
committed
Implement faceting in search
1 parent 7ddd093 commit 9f277a0

File tree

4 files changed

+67
-20
lines changed

4 files changed

+67
-20
lines changed

.pylintrc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ disable=
5555
too-few-public-methods,
5656
line-too-long
5757

58-
5958
[REPORTS]
6059

6160
# Set the output format. Available formats are text, parseable, colorized, msvs

datasets/small_movies.json

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@
44
"title": "Shazam!",
55
"poster": "https://image.tmdb.org/t/p/w1280/xnopI5Xtky18MPhK40cZAGAOVeV.jpg",
66
"overview": "A boy is given the ability to become an adult superhero in times of need with a single magic word.",
7-
"release_date": 1553299200
7+
"release_date": 1553299200,
8+
"genre": "action"
89
},
910
{
1011
"id": "299537",
1112
"title": "Captain Marvel",
1213
"poster": "https://image.tmdb.org/t/p/w1280/AtsgWhDnHTq68L0lLsUrCnM7TjG.jpg",
1314
"overview": "The story follows Carol Danvers as she becomes one of the universe’s most powerful heroes when Earth is caught in the middle of a galactic war between two alien races. Set in the 1990s, Captain Marvel is an all-new adventure from a previously unseen period in the history of the Marvel Cinematic Universe.",
14-
"release_date": 1551830400
15+
"release_date": 1551830400,
16+
"genre": "action"
1517
},
1618
{
1719
"id": "522681",
@@ -25,7 +27,8 @@
2527
"title": "How to Train Your Dragon: The Hidden World",
2628
"poster": "https://image.tmdb.org/t/p/w1280/xvx4Yhf0DVH8G4LzNISpMfFBDy2.jpg",
2729
"overview": "As Hiccup fulfills his dream of creating a peaceful dragon utopia, Toothless’ discovery of an untamed, elusive mate draws the Night Fury away. When danger mounts at home and Hiccup’s reign as village chief is tested, both dragon and rider must make impossible decisions to save their kind.",
28-
"release_date": 1546473600
30+
"release_date": 1546473600,
31+
"genre": "cartoon"
2932
},
3033
{
3134
"id": "450465",
@@ -46,14 +49,16 @@
4649
"title": "Dumbo",
4750
"poster": "https://image.tmdb.org/t/p/w1280/279PwJAcelI4VuBtdzrZASqDPQr.jpg",
4851
"overview": "A young elephant, whose oversized ears enable him to fly, helps save a struggling circus, but when the circus plans a new venture, Dumbo and his friends discover dark secrets beneath its shiny veneer.",
49-
"release_date": 1553644800
52+
"release_date": 1553644800,
53+
"genre": "cartoon"
5054
},
5155
{
5256
"id": "299536",
5357
"title": "Avengers: Infinity War",
5458
"poster": "https://image.tmdb.org/t/p/w1280/7WsyChQLEftFiDOVTGkv3hFpyyt.jpg",
5559
"overview": "As the Avengers and their allies have continued to protect the world from threats too large for any one hero to handle, a new danger has emerged from the cosmic shadows: Thanos. A despot of intergalactic infamy, his goal is to collect all six Infinity Stones, artifacts of unimaginable power, and use them to inflict his twisted will on all of reality. Everything the Avengers have fought for has led up to this moment - the fate of Earth and existence itself has never been more uncertain.",
56-
"release_date": 1524618000
60+
"release_date": 1524618000,
61+
"genre": "action"
5762
},
5863
{
5964
"id": "458723",
@@ -74,21 +79,24 @@
7479
"title": "Cars",
7580
"poster": "https://image.tmdb.org/t/p/w1280/5damnMcRFKSjhCirgX3CMa88MBj.jpg",
7681
"overview": "Lightning McQueen, a hotshot rookie race car driven to succeed, discovers that life is about the journey, not the finish line, when he finds himself unexpectedly detoured in the sleepy Route 66 town of Radiator Springs. On route across the country to the big Piston Cup Championship in California to compete against two seasoned pros, McQueen gets to know the town's offbeat characters.",
77-
"release_date": 1149728400
82+
"release_date": 1149728400,
83+
"genre": "cartoon"
7884
},
7985
{
8086
"id": "299534",
8187
"title": "Avengers: Endgame",
8288
"poster": "https://image.tmdb.org/t/p/w1280/dHjLaIUHXcMBt7YxK1TKWK1end9.jpg",
8389
"overview": "After the devastating events of Avengers: Infinity War, the universe is in ruins due to the efforts of the Mad Titan, Thanos. With the help of remaining allies, the Avengers must assemble once more in order to undo Thanos' actions and restore order to the universe once and for all, no matter what consequences may be in store.",
84-
"release_date": 1556067600
90+
"release_date": 1556067600,
91+
"genre": "action"
8592
},
8693
{
8794
"id": "324857",
8895
"title": "Spider-Man: Into the Spider-Verse",
8996
"poster": "https://image.tmdb.org/t/p/w1280/iiZZdoQBEYBv6id8su7ImL0oCbD.jpg",
9097
"overview": "Miles Morales is juggling his life between being a high school student and being a spider-man. When Wilson 'Kingpin' Fisk uses a super collider, others from across the Spider-Verse are transported to this dimension.",
91-
"release_date": 1544140800
98+
"release_date": 1544140800,
99+
"genre": "action"
92100
},
93101
{
94102
"id": "157433",
@@ -137,7 +145,8 @@
137145
"title": "Aquaman",
138146
"poster": "https://image.tmdb.org/t/p/w1280/5Kg76ldv7VxeX9YlcQXiowHgdX6.jpg",
139147
"overview": "Once home to the most advanced civilization on Earth, Atlantis is now an underwater kingdom ruled by the power-hungry King Orm. With a vast army at his disposal, Orm plans to conquer the remaining oceanic people and then the surface world. Standing in his way is Arthur Curry, Orm's half-human, half-Atlantean brother and true heir to the throne.",
140-
"release_date": 1544140800
148+
"release_date": 1544140800,
149+
"genre": "action"
141150
},
142151
{
143152
"id": "512196",
@@ -186,7 +195,8 @@
186195
"title": "Fantastic Beasts: The Crimes of Grindelwald",
187196
"poster": "https://image.tmdb.org/t/p/w1280/fMMrl8fD9gRCFJvsx0SuFwkEOop.jpg",
188197
"overview": "Gellert Grindelwald has escaped imprisonment and has begun gathering followers to his cause—elevating wizards above all non-magical beings. The only one capable of putting a stop to him is the wizard he once called his closest friend, Albus Dumbledore. However, Dumbledore will need to seek help from the wizard who had thwarted Grindelwald once before, his former student Newt Scamander, who agrees to help, unaware of the dangers that lie ahead. Lines are drawn as love and loyalty are tested, even among the truest friends and family, in an increasingly divided wizarding world.",
189-
"release_date": 1542153600
198+
"release_date": 1542153600,
199+
"genre": "fantasy"
190200
},
191201
{
192202
"id": "399579",

meilisearch/index.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import json
12
import urllib
23
from datetime import datetime
34
from time import sleep
@@ -228,7 +229,8 @@ def get_stats(self):
228229
)
229230
)
230231

231-
def search(self, query, opt_params=None):
232+
# pylint: disable=dangerous-default-value
233+
def search(self, query, opt_params={}):
232234
"""Search in meilisearch
233235
234236
Parameters
@@ -243,13 +245,16 @@ def search(self, query, opt_params=None):
243245
results: `dict`
244246
Dictionnary with hits, offset, limit, processingTime and initial query
245247
"""
246-
if opt_params is None:
247-
opt_params = {}
248-
search_param = {'q': query}
248+
# Query parameters parsing
249249
for key in opt_params:
250-
if isinstance(opt_params[key], list):
250+
if 'facetsDistribution' in opt_params.keys() or 'facetFilters' in opt_params.keys():
251+
opt_params[key] = json.dumps(opt_params[key])
252+
elif isinstance(opt_params[key], list):
251253
opt_params[key] = ','.join(opt_params[key])
252-
params = {**search_param, **opt_params}
254+
params = {
255+
'q': query,
256+
**opt_params
257+
}
253258
return self.http.get(
254259
'{}/{}/{}?{}'.format(
255260
self.config.paths.index,

meilisearch/tests/index/test_index_search_meilisearch.py

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def test_custom_search(self):
5353
assert '_formatted' in response['hits'][0]
5454
assert 'dragon' in response['hits'][0]['_formatted']['title'].lower()
5555

56-
def test_basic_search_params_with_wildcard(self):
56+
def test_custom_search_params_with_wildcard(self):
5757
"""Tests search with '*' in query params"""
5858
response = self.index.search(
5959
'a',
@@ -69,7 +69,7 @@ def test_basic_search_params_with_wildcard(self):
6969
assert '_formatted' in response['hits'][0]
7070
assert "title" in response['hits'][0]['_formatted']
7171

72-
def test_basic_search_params_with_simple_string(self):
72+
def test_custom_search_params_with_simple_string(self):
7373
"""Tests search with simple string in query params"""
7474
response = self.index.search(
7575
'a',
@@ -86,7 +86,7 @@ def test_basic_search_params_with_simple_string(self):
8686
assert 'title' in response['hits'][0]['_formatted']
8787
assert not 'release_date' in response['hits'][0]['_formatted']
8888

89-
def test_basic_search_params_with_string_list(self):
89+
def test_custom_search_params_with_string_list(self):
9090
"""Tests search with string list in query params"""
9191
response = self.index.search(
9292
'a',
@@ -103,3 +103,36 @@ def test_basic_search_params_with_string_list(self):
103103
assert not 'release_date' in response['hits'][0]
104104
assert 'title' in response['hits'][0]['_formatted']
105105
assert not 'overview' in response['hits'][0]['_formatted']
106+
107+
def test_custom_search_params_with_facets_distribution(self):
108+
update = self.index.update_attributes_for_faceting(['genre'])
109+
self.index.wait_for_pending_update(update['updateId'])
110+
response = self.index.search(
111+
'world',
112+
{
113+
'facetsDistribution': ['genre']
114+
}
115+
)
116+
assert isinstance(response, object)
117+
assert len(response['hits']) == 12
118+
assert 'facetsDistribution' in response
119+
assert 'exhaustiveFacetsCount' in response
120+
assert response['exhaustiveFacetsCount']
121+
assert 'genre' in response['facetsDistribution']
122+
assert response['facetsDistribution']['genre']['cartoon'] == 1
123+
assert response['facetsDistribution']['genre']['action'] == 3
124+
assert response['facetsDistribution']['genre']['fantasy'] == 1
125+
126+
def test_custom_search_params_with_facet_filters(self):
127+
update = self.index.update_attributes_for_faceting(['genre'])
128+
self.index.wait_for_pending_update(update['updateId'])
129+
response = self.index.search(
130+
'world',
131+
{
132+
'facetFilters': [['genre:action']]
133+
}
134+
)
135+
assert isinstance(response, object)
136+
assert len(response['hits']) == 3
137+
assert 'facetsDistribution' not in response
138+
assert 'exhaustiveFacetsCount' not in response

0 commit comments

Comments
 (0)