Flask/Mongoengine:尝试使用静态方法对父 class 执行全文搜索时出错
Flask/Mongoengine : Error while trying to perform full-text-search on parent class with static method
我创建了一个 Item class,以及两个子classes Item1 和 Item2,如下所示
class Item(db.Document):
name = db.StringField()
slug = db.StringField()
description = db.StringField()
content = db.StringField()
start_time = db.DateTimeField()
end_time = db.DateTimeField()
@staticmethod
def search_static(keywords):
return Item.objects.search_text(keywords).order_by('$text_score')
@classmethod
def search_class(cls,keywords):
return cls.objects.search_text(keywords).order_by('$text_score')
meta = {
'allow_inheritance' : True,
'indexes' : [
{
'fields': ['$name','$slug','$description','$content'],
'default_language':'french',
'weights': {'name': 10, 'slug': 10 , 'description': 5, 'content': 5}
}
]
}
class Item1(Item):
item_type = db.ReferenceField('T1')
class Item2(Item):
item_type = db.ReferenceField('T2')
class T1(db.Document):
name = db.StringField()
class T2(db.Document):
name = db.StringField()
接下来,我创建了一些项目
Results in mongo shell of following commands db.item.find() / db.t1.find() / db.t2.find()
当我测试 class 方法时一切正常
>>> Item1.search_class("dog")
[<Item1: Item1 object>, <Item1: Item1 object>]
>>> Item1.search_class("viper")
[<Item1: Item1 object>]
>>> Item2.search_class("viper")
[<Item2: Item2 object>]
>>> Item2.search_class("tiger")
[]
>>>
但是当我想使用静态方法时(为了一次搜索所有子classes),我有这个mongo错误:
>>> Item.search_static("tiger")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/venv/lib/python2.7/site-packages/mongoengine/queryset/queryset.py", line 58, in __repr__
self._populate_cache()
File "/venv/lib/python2.7/site-packages/mongoengine/queryset/queryset.py", line 92, in _populate_cache
self._result_cache.append(self.next())
File "/venv/lib/python2.7/site-packages/mongoengine/queryset/base.py", line 1407, in next
raw_doc = self._cursor.next()
File "/venv/lib/python2.7/site-packages/pymongo/cursor.py", line 1090, in next
if len(self.__data) or self._refresh():
File "/venv/lib/python2.7/site-packages/pymongo/cursor.py", line 1012, in _refresh
self.__read_concern))
File "/venv/lib/python2.7/site-packages/pymongo/cursor.py", line 905, in __send_message
helpers._check_command_response(doc['data'][0])
File "/venv/lib/python2.7/site-packages/pymongo/helpers.py", line 196, in _check_command_response
raise OperationFailure(msg % errmsg, code, response)
pymongo.errors.OperationFailure: error processing query: ns=archives_flask.itemTree: $and
_cls $in [ "Item" "Item.Item1" "Item.Item2" ]
TEXT : query=tiger, language=french, caseSensitive=0, diacriticSensitive=0, tag=NULL
Sort: { _text_score: { $meta: "textScore" } }
Proj: { _text_score: { $meta: "textScore" } }
planner returned error: failed to use text index to satisfy $text query (if text index is compound, are equality predicates given for all prefix fields?)
>>>
能否请您提供任何想法或提示?
我意识到这是一个很老的问题,但我在寻找完全相同问题的解决方案时发现了它,我想我会在这里记录我的发现以供后代使用。
问题是,当您 subclass a mongoengine.Document
subclass 时,mongoengine 会自动添加 _cls
作为集合的索引。当您随后尝试使用父 class(Document 的直接子class)对该集合进行全文搜索时,mongoengine
将在查询此文档及其所有子 class 的所有可能 _cls
值。不幸的是,这是不允许的,as documented in the MongoDB docs:
If the compound text index includes keys preceding the text index key, to perform a $text search, the query predicate must include equality match conditions on the preceding keys.
请注意,如果您对其中一个子classes 进行文本搜索,它会完美运行 - 这是因为 mongoengine 在这种情况下使用相等谓词,这是完全有效的。
您可以通过将索引调整为不使用复合文本索引来解决此问题。在您的父文件 subclass(在本例中为 Item)调整您的 indexes
定义以将 cls
设置为 False
:
meta = {
'allow_inheritance' : True,
'indexes' : [
{
'fields': ['$name','$slug','$description','$content'],
'default_language':'french',
'weights': {'name': 10, 'slug': 10 , 'description': 5, 'content': 5},
'cls': False
}
]
}
这记录在 Mongoengine documentation 中。
我希望这对以后遇到这个问题的人有所帮助!
我创建了一个 Item class,以及两个子classes Item1 和 Item2,如下所示
class Item(db.Document):
name = db.StringField()
slug = db.StringField()
description = db.StringField()
content = db.StringField()
start_time = db.DateTimeField()
end_time = db.DateTimeField()
@staticmethod
def search_static(keywords):
return Item.objects.search_text(keywords).order_by('$text_score')
@classmethod
def search_class(cls,keywords):
return cls.objects.search_text(keywords).order_by('$text_score')
meta = {
'allow_inheritance' : True,
'indexes' : [
{
'fields': ['$name','$slug','$description','$content'],
'default_language':'french',
'weights': {'name': 10, 'slug': 10 , 'description': 5, 'content': 5}
}
]
}
class Item1(Item):
item_type = db.ReferenceField('T1')
class Item2(Item):
item_type = db.ReferenceField('T2')
class T1(db.Document):
name = db.StringField()
class T2(db.Document):
name = db.StringField()
接下来,我创建了一些项目
Results in mongo shell of following commands db.item.find() / db.t1.find() / db.t2.find()
当我测试 class 方法时一切正常
>>> Item1.search_class("dog")
[<Item1: Item1 object>, <Item1: Item1 object>]
>>> Item1.search_class("viper")
[<Item1: Item1 object>]
>>> Item2.search_class("viper")
[<Item2: Item2 object>]
>>> Item2.search_class("tiger")
[]
>>>
但是当我想使用静态方法时(为了一次搜索所有子classes),我有这个mongo错误:
>>> Item.search_static("tiger")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/venv/lib/python2.7/site-packages/mongoengine/queryset/queryset.py", line 58, in __repr__
self._populate_cache()
File "/venv/lib/python2.7/site-packages/mongoengine/queryset/queryset.py", line 92, in _populate_cache
self._result_cache.append(self.next())
File "/venv/lib/python2.7/site-packages/mongoengine/queryset/base.py", line 1407, in next
raw_doc = self._cursor.next()
File "/venv/lib/python2.7/site-packages/pymongo/cursor.py", line 1090, in next
if len(self.__data) or self._refresh():
File "/venv/lib/python2.7/site-packages/pymongo/cursor.py", line 1012, in _refresh
self.__read_concern))
File "/venv/lib/python2.7/site-packages/pymongo/cursor.py", line 905, in __send_message
helpers._check_command_response(doc['data'][0])
File "/venv/lib/python2.7/site-packages/pymongo/helpers.py", line 196, in _check_command_response
raise OperationFailure(msg % errmsg, code, response)
pymongo.errors.OperationFailure: error processing query: ns=archives_flask.itemTree: $and
_cls $in [ "Item" "Item.Item1" "Item.Item2" ]
TEXT : query=tiger, language=french, caseSensitive=0, diacriticSensitive=0, tag=NULL
Sort: { _text_score: { $meta: "textScore" } }
Proj: { _text_score: { $meta: "textScore" } }
planner returned error: failed to use text index to satisfy $text query (if text index is compound, are equality predicates given for all prefix fields?)
>>>
能否请您提供任何想法或提示?
我意识到这是一个很老的问题,但我在寻找完全相同问题的解决方案时发现了它,我想我会在这里记录我的发现以供后代使用。
问题是,当您 subclass a mongoengine.Document
subclass 时,mongoengine 会自动添加 _cls
作为集合的索引。当您随后尝试使用父 class(Document 的直接子class)对该集合进行全文搜索时,mongoengine
将在查询此文档及其所有子 class 的所有可能 _cls
值。不幸的是,这是不允许的,as documented in the MongoDB docs:
If the compound text index includes keys preceding the text index key, to perform a $text search, the query predicate must include equality match conditions on the preceding keys.
请注意,如果您对其中一个子classes 进行文本搜索,它会完美运行 - 这是因为 mongoengine 在这种情况下使用相等谓词,这是完全有效的。
您可以通过将索引调整为不使用复合文本索引来解决此问题。在您的父文件 subclass(在本例中为 Item)调整您的 indexes
定义以将 cls
设置为 False
:
meta = {
'allow_inheritance' : True,
'indexes' : [
{
'fields': ['$name','$slug','$description','$content'],
'default_language':'french',
'weights': {'name': 10, 'slug': 10 , 'description': 5, 'content': 5},
'cls': False
}
]
}
这记录在 Mongoengine documentation 中。 我希望这对以后遇到这个问题的人有所帮助!