Skip to content

Commit 6ee6897

Browse files
authored
Merge pull request #2794 from bagerard/add_text_score_to_search_text
add ability to turn off text_score computation on search_text call
2 parents dda51bd + a4051a5 commit 6ee6897

File tree

4 files changed

+23
-6
lines changed

4 files changed

+23
-6
lines changed

docs/changelog.rst

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ Development
1919
as it was useless and making it look like it was returning a different class although it was the same.
2020
Thus, it must be called like `with no_dereference(User):` and no longer `with no_dereference(User) as ...:`
2121
- Added __raw__ to :meth:`~mongoengine.Queryset.order_by()` to allow to provide raw pymongo 'sort' argument and get around some of the limitations #2783
22+
- Add `text_score` argument on :meth:`~mongoengine.Document.search_text()` to allow text_score computation to be turned off
23+
as it interfer with natural returned documents order #2759
2224

2325
Changes in 0.27.0
2426
=================

mongoengine/base/document.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ def get_text_score(self):
322322

323323
if "_text_score" not in self._data:
324324
raise InvalidDocumentError(
325-
"This document is not originally built from a text query"
325+
"This document is not originally built from a text query (or text_score was not set on search_text() call)"
326326
)
327327

328328
return self._data["_text_score"]

mongoengine/queryset/base.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ def __init__(self, document, collection):
7171
self._none = False
7272
self._as_pymongo = False
7373
self._search_text = None
74+
self._search_text_score = None
7475

7576
self.__dereference = False
7677
self.__auto_dereference = True
@@ -229,7 +230,7 @@ def filter(self, *q_objs, **query):
229230
"""An alias of :meth:`~mongoengine.queryset.QuerySet.__call__`"""
230231
return self.__call__(*q_objs, **query)
231232

232-
def search_text(self, text, language=None):
233+
def search_text(self, text, language=None, text_score=True):
233234
"""
234235
Start a text search, using text indexes.
235236
Require: MongoDB server version 2.6+.
@@ -239,6 +240,8 @@ def search_text(self, text, language=None):
239240
If not specified, the search uses the default language of the index.
240241
For supported languages, see
241242
`Text Search Languages <https://docs.mongodb.org/manual/reference/text-search-languages/#text-search-languages>`.
243+
:param text_score: True to have it return the text_score (available through get_text_score()), False to disable that
244+
Note that unless you order the results, leaving text_score=True may provide randomness in the returned documents
242245
"""
243246
queryset = self.clone()
244247
if queryset._search_text:
@@ -252,6 +255,7 @@ def search_text(self, text, language=None):
252255
queryset._mongo_query = None
253256
queryset._cursor_obj = None
254257
queryset._search_text = text
258+
queryset._search_text_score = text_score
255259

256260
return queryset
257261

@@ -833,6 +837,7 @@ def _clone_into(self, new_qs):
833837
"_hint",
834838
"_collation",
835839
"_search_text",
840+
"_search_text_score",
836841
"_max_time_ms",
837842
"_comment",
838843
"_batch_size",
@@ -1673,7 +1678,8 @@ def _cursor_args(self):
16731678
if fields_name not in cursor_args:
16741679
cursor_args[fields_name] = {}
16751680

1676-
cursor_args[fields_name]["_text_score"] = {"$meta": "textScore"}
1681+
if self._search_text_score:
1682+
cursor_args[fields_name]["_text_score"] = {"$meta": "textScore"}
16771683

16781684
return cursor_args
16791685

tests/queryset/test_queryset.py

+12-3
Original file line numberDiff line numberDiff line change
@@ -3692,7 +3692,7 @@ class News(Document):
36923692
"t2", language="french"
36933693
)
36943694

3695-
def test_text_indexes(self):
3695+
def test_search_text(self):
36963696
class News(Document):
36973697
title = StringField()
36983698
content = StringField()
@@ -3751,14 +3751,16 @@ class News(Document):
37513751
assert "dilma" in new.content
37523752
assert "planejamento" in new.title
37533753

3754-
query = News.objects.search_text("candidata")
3754+
query = News.objects.search_text("candidata", text_score=True)
37553755
assert query._search_text == "candidata"
37563756
new = query.first()
37573757

37583758
assert isinstance(new.get_text_score(), float)
37593759

37603760
# count
3761-
query = News.objects.search_text("brasil").order_by("$text_score")
3761+
query = News.objects.search_text("brasil", text_score=True).order_by(
3762+
"$text_score"
3763+
)
37623764
assert query._search_text == "brasil"
37633765

37643766
assert query.count() == 3
@@ -3778,6 +3780,13 @@ class News(Document):
37783780
item = News.objects.search_text("brasil").order_by("$text_score").first()
37793781
assert item.get_text_score() == max_text_score
37803782

3783+
# Verify query reproducibility when text_score is disabled
3784+
# Following wouldn't work for text_score=True #2759
3785+
for i in range(10):
3786+
qs1 = News.objects.search_text("brasil", text_score=False)
3787+
qs2 = News.objects.search_text("brasil", text_score=False)
3788+
assert list(qs1) == list(qs2)
3789+
37813790
def test_distinct_handles_references_to_alias(self):
37823791
register_connection("testdb", "mongoenginetest2")
37833792

0 commit comments

Comments
 (0)