@@ -134,6 +134,127 @@ def test_more_like_this_by_document() -> None:
134134 assert ids == {12 }
135135
136136
137+ def test_more_like_this_with_stopwords () -> None :
138+ """MLT with stopwords excludes terms from matching - verified by comparing results."""
139+ # Get baseline results without stopwords
140+ baseline_ids = _ids (
141+ MockItem .objects .filter (
142+ MoreLikeThis (
143+ product_id = 3 , # "Sleek running shoes"
144+ fields = ["description" ],
145+ )
146+ )
147+ )
148+
149+ # Get results with "shoes" as stopword
150+ with_stopword_ids = _ids (
151+ MockItem .objects .filter (
152+ MoreLikeThis (
153+ product_id = 3 ,
154+ fields = ["description" ],
155+ stopwords = ["shoes" ],
156+ )
157+ )
158+ )
159+
160+ # Source item always included in both
161+ assert 3 in baseline_ids
162+ assert 3 in with_stopword_ids
163+
164+ # With "shoes" as stopword, results should be different
165+ # (fewer matches since "shoes" term is excluded from matching)
166+ assert (
167+ with_stopword_ids != baseline_ids
168+ ), "Stopwords should change the results - excluding 'shoes' should remove shoe-related matches"
169+
170+ # Typically, stopwords should reduce the number of matches
171+ # (unless all matches are from other terms like "running")
172+ assert len (with_stopword_ids ) <= len (
173+ baseline_ids
174+ ), "Stopwords should not increase match count"
175+
176+
177+ def test_more_like_this_with_word_length () -> None :
178+ """MLT with min/max word length filters terms - verified by comparing results."""
179+ # Get baseline without word length filter
180+ baseline_ids = _ids (
181+ MockItem .objects .filter (
182+ MoreLikeThis (
183+ product_id = 3 , # "Sleek running shoes"
184+ fields = ["description" ],
185+ )
186+ )
187+ )
188+
189+ # Get results with min_word_length=6 (filters out "shoes" which is 5 chars)
190+ with_min_length_ids = _ids (
191+ MockItem .objects .filter (
192+ MoreLikeThis (
193+ product_id = 3 ,
194+ fields = ["description" ],
195+ min_word_length = 6 ,
196+ )
197+ )
198+ )
199+
200+ # Source item always included
201+ assert 3 in baseline_ids
202+ assert 3 in with_min_length_ids
203+
204+ # Results should differ when short words are filtered
205+ assert (
206+ with_min_length_ids != baseline_ids
207+ ), "min_word_length=6 should filter out 'shoes' (5 chars) and change results"
208+
209+
210+ def test_more_like_this_stopwords_reversible () -> None :
211+ """Verify stopwords effect is consistent and reversible."""
212+ # First query with stopwords
213+ ids_with = _ids (
214+ MockItem .objects .filter (
215+ MoreLikeThis (
216+ product_id = 3 ,
217+ fields = ["description" ],
218+ stopwords = ["shoes" ], # The main matching term
219+ )
220+ )
221+ )
222+
223+ # Second query without stopwords (baseline)
224+ ids_without = _ids (
225+ MockItem .objects .filter (
226+ MoreLikeThis (
227+ product_id = 3 ,
228+ fields = ["description" ],
229+ )
230+ )
231+ )
232+
233+ # Third query with same stopwords again - should be consistent
234+ ids_with_again = _ids (
235+ MockItem .objects .filter (
236+ MoreLikeThis (
237+ product_id = 3 ,
238+ fields = ["description" ],
239+ stopwords = ["shoes" ],
240+ )
241+ )
242+ )
243+
244+ # Stopwords should produce consistent results (deterministic)
245+ assert ids_with == ids_with_again , "Same stopwords should produce same results"
246+
247+ # With "shoes" as stopword, we should have fewer or equal matches
248+ # (excluding the main matching term reduces similarity matches)
249+ assert len (ids_with ) <= len (
250+ ids_without
251+ ), "Stopwords should not increase match count"
252+
253+ # Source item always included regardless of stopwords
254+ assert 3 in ids_with
255+ assert 3 in ids_without
256+
257+
137258def test_metadata_color_literal_search () -> None :
138259 """Search over JSON color subfield should return the silver items."""
139260 with connection .cursor () as cursor :
0 commit comments