【问题标题】:How to create autocomplete with GAE?如何使用 GAE 创建自动完成功能?
【发布时间】:2011-10-17 15:14:53
【问题描述】:

我使用 jQuery UI autocomplete widget。我也有 GAE 数据存储:

class Person(db.Model):
    # key_name contains person id in format 'lastname-firstname-middlename-counter',
    # counter and leading dash are omitted, if counter=0
    first_name = db.StringProperty()
    last_name = db.StringProperty()
    middle_name = db.StringProperty()

当用户可以输入姓氏、名字和/或中间名时,我如何在自动完成小部件中搜索此人?

所以,我将用户输入字符串设为self.request.get('term')。我应该如何在我的数据存储中搜索相同的内容(因为我需要查看每个字段,并且可能需要查看 3 个字段的组合值)?如何优化这样的查询? 我也不清楚应该是什么回复格式。 jQuery 文档说:

数据源可以是:

an Array with local data
a String, specifying a URL
a Callback

本地数据可以是简单的字符串数组,也可以包含 数组中每个项目的对象,带有标签或值 财产或两者兼而有之。

【问题讨论】:

  • 然后呢?你试过什么?你到底有什么问题?
  • 我已经用更多细节更新了这个问题。

标签: google-app-engine jquery-ui google-cloud-datastore


【解决方案1】:

这里有一些巧妙的技巧。考虑这个增强模型:

class Person(db.Model):
  first_name = db.StringProperty()
  last_name = db.StringProperty()
  middle_name = db.StringProperty()
  names_lower = db.StringListProperty()

您需要使 names_lower 与真实字段保持同步,例如:

p.names_lower = [p.first_name.lower(), p.last_name.lower(),
                 p.middle_name.lower()]

您可以使用DerivedProperty 更优雅地做到这一点。

现在,您的查询:

term = self.request.get('term').lower()
query = Person.all()
query.filter('names_lower >=', term)
query.filter('names_lower <=', unicode(term) + u"\ufffd")

这给了你:

  • 用一个索引匹配所有 3 个属性
  • 不区分大小写的匹配
  • 通配符后缀匹配

因此,在任何情况下,对“smi”的查询都将返回任何姓名以“smi”开头的任何人。

将小写名称复制到 ListProperty 可以实现不区分大小写的匹配,并允许我们用一个查询搜索所有 3 个字段。 "\ufffd" 是最高可能的 unicode 字符,因此它是我们的子字符串匹配的上限。如果出于某种原因您想要完全匹配,请过滤 'names_lower =', term

编辑

我应该如何在我的数据存储中搜索相同的内容(因为我需要查看 在每个字段,可能是 3 个字段的组合值)?如何 优化这样的查询?

这已在原始解决方案中进行了说明。通过获取 3 个字段并将它们复制到单个 ListProperty,我们实际上是在创建一个索引,其中每个人有多个条目。如果我们有一个名为 Bob J Smith 的人,他将在我们的索引中获得 3 次点击:

  • names_lower = 鲍勃
  • names_lower = j
  • names_lower = 史密斯

这消除了对每个字段运行不同查询的需要。

我也不清楚应该是什么回复格式。

仔细阅读the docs。 jQuery 的格式化输出应该非常简单。您的数据源将是一个指定 URL 的字符串,并且您需要将响应格式化为 JSON。

【讨论】:

  • 谢谢,德鲁。如果用户只输入名字(没有中间名)怎么办?这个过滤器不能正常工作,对吧?你能帮我看看结果格式吗?
  • 好答案!但是,如果用户输入了两个或更多单词,您应该对除最后一个单词以外的所有单词使用相等过滤器,并在最后一个单词上使用不等过滤器(例如,“bob smi”会变成Person.all().filter('names_lower =', u'bob').filter('names_lower &gt;=', u'smi').filter('names_lower &lt;', u'smi\ufffd')
  • Drew Sears,@Nick,如果用户输入“mit”(仍然应该找到“smith j bob”),如何组织?
  • 你基本上不能。通配符后缀匹配很容易,因为它可以通过升序属性索引来满足。真正的子字符串匹配需要相当于数据存储不支持的表扫描。您必须从数据存储中获取每条记录并过滤内存中的匹配项。
【解决方案2】:

基本上同意 Drew 写的所有内容,我发布了一个指向 my blog 的链接,其中包含在数据存储区中搜索信息时自动完成选择关键字的详细示例。

所有在 GAE 中使用 Python 完成并使用 YUI3 而不是 jQuery(插入 jQuery 或任何其他库将是微不足道的)。

简而言之,这个想法是数据存储包含一组使用关键字索引的文档(使用关系索引实体)。当用户输入要搜索的单词时,系统会使用这些文档中的关键字自动完成它们。

【讨论】:

    猜你喜欢
    • 2021-06-24
    • 1970-01-01
    • 2021-12-06
    • 2011-05-19
    • 2022-08-15
    • 2015-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多