部分文本匹配GAE

时间:2015-07-08 07:54:46

标签: python-2.7 google-app-engine app-engine-ndb google-cloud-datastore google-app-engine-python

我正在开发一个用于管理客户的Web应用程序。所以我有一个Customer实体,由通常的字段组成,例如first_name,last_name,age等。

我有一个页面,其中这些客户显示为表格。在同一页面中,我有一个搜索字段,我想在用户使用Ajax在搜索字段中键入内容时过滤客户并更新表格。 以下是它应该如何工作:

图1:显示所有客户的主页面: The main page showing all of the customers

图2:只要用户键入字母“b”,表格就会更新结果: As long as the user types letter "b", the table is updated with the results

鉴于GAE不支持部分文本匹配,我已经欺骗并实施了它显示的内容here TL; DR:我创建了一个 Customers Index ,包含每个客户的搜索文档(doc_id = customer_key)。每个搜索文档包含 Atom Fields ,用于我希望能够搜索的每个客户的字段(例如:first_name,last_name):每个字段都是这样组成的:假设last_name是Berlusconi,字段是将由这些 Atom Fields “b”组成“be”“ber”“berl”“berlu”“berlus”“berlusc”“berlusco”“berluscon”“berlusconi” 。 通过这种方式,我能够以类似于部分文本匹配的方式执行全文匹配。如果我搜索“Be”,贝卢斯科尼的客户将被退回。

搜索是通过Ajax调用进行的:每当用户键入搜索字段(ajax稍微喋喋不休地看看用户是否继续键入,以避免发送一连串请求)时,就会调用Ajax查询字符串,并返回一个json对象。

现在,事情在调试方面运行良好,但我在数据存储区中与一些人进行了测试。只要我放了很多人,搜索就会很慢。

这是我创建搜索文档的方式。每次将新客户放入数据存储区时都会调用此方法。

def put_search_document(cls, key):
    """
    Called by _post_put_hook in BaseModel
    """
    model = key.get()
    _fields = []
    if model:
        _fields.append(search.AtomField(name="empty", value=""),)  # to retrieve customers when no query string
        _fields.append(search.TextField(name="sort1", value=model.last_name.lower()))
        _fields.append(search.TextField(name="sort2", value=model.first_name.lower()))

        _fields.append(search.TextField(name="full_name", value=Customer.tokenize1(
            model.first_name.lower()+" "+model.last_name.lower()
            )),)

        _fields.append(search.TextField(name="full_name_rev", value=Customer.tokenize1(
            model.last_name.lower()+" "+model.first_name.lower()
            )),)

        # _fields.append(search.TextField(name="telephone", value=Customer.tokenize1(
        #     model.telephone.lower()
        #     )),)
        # _fields.append(search.TextField(name="email", value=Customer.tokenize1(
        #     model.email.lower()
        #     )),)

        document = search.Document(  # create new document with doc_id=key.urlsafe()
            doc_id=key.urlsafe(),
            fields=_fields)
        index = search.Index(name=cls._get_kind()+"Index")  # not in try-except: defer will catch and retry.
        index.put(document)

@staticmethod
def tokenize1(string):
    s = ""
    for i in range(len(string)):
        if i > 0:
            s = s + " " + string[0:i+1]
        else:
            s = string[0:i+1]
    return s

这是搜索代码:

@staticmethod
def search(ndb_model, query_phrase):
    # TODO: search returns a limited number of results(20 by default)
    # (See Search Results at https://cloud.google.com/appengine/docs/python/search/#Python_Overview)
    sort1 = search.SortExpression(expression='sort1', direction=search.SortExpression.ASCENDING,
                                  default_value="")
    sort2 = search.SortExpression(expression='sort2', direction=search.SortExpression.ASCENDING,
                                  default_value="")
    sort_opt = search.SortOptions(expressions=[sort1, sort2])
    results = search.Index(name=ndb_model._get_kind() + "Index").search(
        search.Query(
            query_string=query_phrase,
            options=search.QueryOptions(
                sort_options=sort_opt
            )
        )
    )

    print "----------------"
    res_list = []
    for r in results:
        obj = ndb.Key(urlsafe=r.doc_id).get()
        print obj.first_name + " "+obj.last_name
        res_list.append(obj)
    return res_list

有没有其他人有同样的经历?如果是这样,你是如何解决的?

非常感谢你们, Marco Galassi

编辑:名字,电子邮件,电话显然是完全发明的。 Edit2 :我现在已经转移到看起来快一点的TextField,但问题仍然存在

0 个答案:

没有答案