9

我喜欢数据存储的简单性,可扩展性和易用性;并且新的ndb库中的增强功能非常棒。正在寻找创意/替代方案来提供页面/项目数量/导航与GAE数据存储查询相匹配的项目

正如我理解的数据存储最佳实践,不应该编写代码来提供匹配查询结果的项目和/或页数,当匹配查询的项目数很大时;因为唯一的方法就是检索所有资源密集型的结果。

但是,在许多应用程序(包括我们的应用程序)中,常见的愿望是查看匹配项的数量,并为用户提供导航到这些结果的特定页面的能力。如文章Paging Through Large Datasets中所述,要求解决提取(限制,偏移量= X)的要求使数据存储区分页问题更加复杂。为了支持推荐的方法,数据必须包含一个可以按照显示结果的方式排序的唯一值列。此列将为每个结果页面定义一个起始值;保存它,我们可以高效地获取相应的页面,允许根据请求导航到特定页面或下一页面。因此,如果您想要以多种方式显示排序结果,则可能需要维护多个此类列。

应该注意的是,从SDK v1.3.1开始,Query Cursors是推荐的数据存储区分页方式。它们有一些限制,包括缺少对IN和!=过滤器操作符的支持。目前,我们的一些重要查询使用IN,但我们会尝试使用来编写它们以用于查询游标。

遵循建议的准则,一个可以给用户一个(下一页)(后退)导航按钮,以及特定页面的按钮导航进行。例如,如果用户按下3次(下一个),该应用程序可以显示以下按钮,记住每个唯一的起始记录或光标以保持导航高效:(上一页)(第1页)(第2页)(Page-3)(Page-4)(Next)

一些人建议分开跟踪计数,但当用户被允许在一组丰富的字段上查询时,这种方法是不实际的,这些字段会改变返回的结果。

我正在寻找一般对这些问题的见解和明确了以下问题:

  1. 你提供什么样的导航选项查询结果的数据存储区的应用程序来解决这些限制?

  2. 如果提供高效结果数量和整个查询结果集的页面导航 用户是当务之急,应使用数据存储 的赞成GAE MySql solution现在所提供的被抛弃。

  3. 大表体系结构或 数据存储实施中是否会有任何即将发生的更改,这些更改将为 提供额外的功能,以有效地计算查询结果?

非常感谢您的帮助。

回答

2

这一切都取决于你通常有多少成绩获得。例如。通过传递.count()一个合适的限制,如果#items是例如< = 100和“多”,如果有更多。这听起来像你不能预先计算所有可能的计数,但至少你可以缓存它们,从而节省了很多数据存储操作。

使用NDB,最有效的方法可以是,以请求使用fetch_page(),然后实体使用所得光标作为起点的第一页为计数()调用;或者,您可能最好使用其异步工具同时运行第一页的fetch()和count()。如果您的查询不支持游标,第二个选项可能是您唯一的选择。大多数IN/OR查询当前不支持游标,但是如果您通过__key__订购,则会执行此操作。

就用户界面选项而言,我认为足以提供下一页和上一页的选项;可以提前跳过几页的“Gooooooogle”UI很可爱,但我几乎从不使用它。 (要实现“上一页”,反向查询的顺序和使用时使用的当前页面相同的光标。我敢肯定,这是保证工作。)

+0

假设我们使用C = query.count(N)方法向用户显示“1-20 of C”或“1-20 of many;我们如何确定一个合理的值,成本明智,对于N.在我们的使用case 100会太小,关于如何最好地调整这个大小以降低成本的建议?来自NDB的文档:“请注意,count(),虽然比fetch()快,但每次调用都会执行很多工作“。使用多少配额? Guido,感谢Python,NDB和您的帮助:) IMO页数和导航是一些应用程序的一个很好的功能,因为用户可以评估和调整与其参数相匹配的数据大小钻进之前。 – 2012-02-23 16:12:18

+1

您可以使用以下页面计算成本:http://code.google.com/appengine/docs/billing.html#Billable_Resource_Unit_Costs。AFAIK Count()就像是一个按键查询。考虑缓存计数。(根据亲如果您的缓存数量有限,则可以使用分片计数器模式将计数存储在数据存储中。) – 2012-02-24 00:30:42

+3

也是IN/OR查询的更新:您可以将任何查询转换为游标 - 通过在现有排序顺序末尾添加__key__排序来支持查询。例如。在NDB中:'Employee.query(Employee.name.IN(['Joe','Jane']))。order(Employee.name,Employee.key).fetch_page(N)' - 没有Employee.key命令它会引发BadArgumentError。 – 2012-02-24 00:47:27

0
  1. 我发现,Gmail是准备与一些计数 - 它可以告诉你,你已经收到一共有多少邮件,多少是在您的收件箱,等等 - 但在其他罪名,如全文搜索它说你正在看“许多1-20”或“约130的1-20”。你真的需要为每个查询显示计数,还是可以预先计算重要的计数?
+0

保持一个众所周知的总数跟踪绝对容易。在我读过的一些文章中,人们在GAE上使用了分片计数器:http://code.google.com/appengine/articles/sharding_counters.html。我们的用例更像gmail全文搜索。我认为显示总计和页面导航可以让用户在钻取之前更好地理解他们的搜索结果。也就是说,如果用户使用数据存储,唯一的选择是“许多”中的“1-20”方法在这里禁止了一些启示。当结果集很小时,可能通过向前看,可能gmail会显示“约130的1-20”。 – 2012-02-22 20:57:22

1

也许只是瞄准这种风格的分页:

(第一)(上一页)(第1页)(第2页)(第3页)......(最后)(下)

这样不需要总数 - 你只需要你的代码要知道另外3个页面有足够的结果。页面大小为每页10个项目,你只需要知道有30多个项目。

如果您有第60页的内容(足够用于6页),那么您的代码会向前看,并且只会看到另外20条记录,因此您可以显示最后一个页码:

(第一)(上一页)(4页)(第5页)(第6页)(下)(末)

基本上每个抓取当前页面,只需获取足够的记录,另外3个数据页面,指望他们看看你有多少页面,然后相应地显示你的寻呼机。

另外,如果你只取钥匙,它会比获取额外的项目,更高效。 希望能有所帮助!! ?? :)

+0

嗨@Joe谢谢你的建议。你已经捕获了我在原始问题的第5段中所描述的内容。 Guido的回答突出了可能的重点。考虑到计数查询的成本,对于大数据集,当N小于结果总数时,我们肯定会使用类似“...”的内容。请参阅Guido的答案下的讨论以获取更多背景。 – 2012-03-05 22:06:49

0

由于议题“寻找想法/替代品提供了一个页面”,也许取10页值得key_only项目,然后通过内这一套是值得考虑的操作导航的非常简单的替代。

我已经回答过类似的问题阐述了这一点,你会发现有示例代码:

Backward pagination with cursor is working but missing an item

的示例代码会更适合这个问题。这是它的一部分:

def session_list(): 
    page = request.args.get('page', 0, type=int) 

    sessions_keys = Session.query().order(-Session.time_opened).fetch(100, keys_only=True) 
    sessions_keys, paging = generic_list_paging(sessions_keys, page) 
    # generic_list_paging will select the proper sublist. 
    sessions = [ sk.get() for sk in sessions_keys ] 

    return render_template('generic_list.html', objects=sessions, paging=paging) 

有关更多代码,请参阅参考问题。

当然,如果结果集可能很大,那么仍然必须给出一些限制,硬性限制是我认为的1000个项目。显然,它的结果长达10多页,用户将被要求通过添加标准来完善。

在数百个keys_only项目中处理分页真的非常简单,因此绝对值得考虑。它可以很容易地提供问题中提到的直接页面导航。实际的实体项目只能用于实际的当前页面,其余的仅仅是密钥,所以它并不昂贵。您可以考虑将keys_only结果集保留在memcache中几分钟,以便快速浏览页面的用户不需要再次执行相同的查询。