代码之家  ›  专栏  ›  技术社区  ›  bassory99

Flask/Mongoengine:尝试使用静态方法对父类执行全文搜索时出错

  •  1
  • bassory99  · 技术社区  · 8 年前

    我创建了一个Item类,以及两个子类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()

    当我测试类方法时,一切都很好

    >>> 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")
    []
    >>> 
    

    但是,当我想使用静态方法(为了一次搜索所有子类)时,我有一个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?)
    >>> 
    

    你能提供一些想法或建议吗?

    1 回复  |  直到 8 年前
        1
  •  2
  •   Thomas Storey    8 年前

    我意识到这是一个相当古老的问题,但我是在寻找完全相同的问题的解决方案时发现的,我想我会把我的发现记录在这里,以供后代参考。

    问题是,当您将 mongoengine.Document 子类,mongoengine自动添加 _cls 作为集合上的索引。当您随后尝试使用父类(Document的直接子类)对该集合进行全文搜索时, mongoengine 将包括一个 $in 查询中所有可能的 _cls公司 此文档及其所有子类的值。不幸的是,这是不允许的, as documented in the MongoDB docs :

    如果复合文本索引在文本索引键之前包含键,则要执行$text搜索,查询谓词必须在前面的键上包含相等匹配条件。

    请注意,如果您在其中一个子类上执行文本搜索,它将非常有效-这是因为mongoengine在这种情况下使用了一个完全有效的等式谓词。

    可以通过调整索引以不使用复合文本索引来解决此问题。在父文档子类(本例中为项目)上,调整您的 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 . 我希望这对以后遇到这个问题的人有帮助!