gpt4 book ai didi

python - GAE 数据存储 - 写入多于读取时的最佳实践

转载 作者:行者123 更新时间:2023-11-28 17:53:26 24 4
gpt4 key购买 nike

我正在尝试使用 GAE 数据存储进行一些练习,以了解查询和计费机制。

我已经阅读了关于 GAE 的 Oreilly 书籍,并观看了关于数据存储的 Google 视频。我的问题是,最佳实践方法通常涉及对数据存储的读取多于写入。

我构建了一个 super 简单的应用程序:

  • 有两个网页 - 一个到选择链接,并选择一个 View 链接
  • 每个用户都可以选择将 url 链接添加到他的“链接提要”
  • 用户可以随时选择任意数量的链接。
  • 在不同的网页上,我想向用户显示他最近选择的 10 个链接。
  • 每个用户都有自己的“链接提要”网页。
  • 在我想保存和显示一些元数据的每个“链接”上——例如:url 链接本身;什么时候选择的;它已经出现在 Feed 上多少次;等

在这种情况下,由于用户可以选择任意数量的链接,只要他愿意,我的应用程序写入数据存储区的次数远远超过读取次数(写入 - 当用户选择另一个链接时;读取 - 当用户打开网页查看他的“链接提要”)

问题 1:我可以想到(至少)两个选项来处理这个应用程序的数据:

选项 A:- 使用用户详细信息、注册等维护每个用户的实体- 为每个用户维护另一个实体,其中包含他最近选择的 10 个链接,这些链接将在用户请求后呈现到用户的网页上

选项 B:- 维护每个 url 链接的实体 - 这意味着所有用户的所有 url 将存储为同一对象- 维护每个用户详细信息的实体(与选项 A 中相同),但在 url 的大表中添加对用户 url 的引用

什么是更好的方法?

问题 2:如果我想计算到今天为止选择的 url 总数,或者用户每天选择的 url 数量,或者任何其他计数——我应该将它与我的 SDK 工具一起使用,还是应该在我上面描述的实体中插入计数器? (我想尽可能减少数据存储的写入量)

编辑(回答@Elad 的评论):假设我只想为每个用户保存最后 10 个 url。其余的我想摆脱(这样就不会用不必要的数据填充我的数据库)。

编辑 2:添加代码后所以我尝试使用以下代码(首先尝试 Elad 的方法):

这是我的类(class):

class UserChannel(db.Model):
currentUser = db.UserProperty()
userCount = db.IntegerProperty(default=0)
currentList = db.StringListProperty() #holds the last 20-30 urls

然后我将 url 和元数据序列化为 JSON 字符串,用户从第一页发布。以下是 POST 的处理方式:

def post(self):
user = users.get_current_user()
if user:
logging messages for debugging
self.response.headers['Content-Type'] = 'text/html'
#self.response.out.write('<p>the user_id is: %s</p>' % user.user_id())
updating the new item that user adds
current_user = UserChannel.get_by_key_name(user.nickname())
dataJson = self.request.get('dataJson')
#self.response.out.write('<p>the dataJson is: %s</p>' % dataJson)
current_user.currentPlaylist.append(dataJson)
sizePlaylist= len(current_user.currentPlaylist)
self.response.out.write('<p>size of currentplaylist is: %s</p>' % sizePlaylist)
#whenever the list gets to 30 I cut it to be 20 long
if sizePlaylist > 30:
for i in range (0,9):
current_user.currentPlaylist.pop(i)
current_user.userCount +=1
current_user.put()
Updater().send_update(dataJson)
else:
self.response.headers['Content-Type'] = 'text/html'
self.response.out.write('user_not_logged_in')

其中 Updater 是我使用 Channel-API 更新带有提要的网页的方法。

现在,一切正常,我可以看到每个用户都有一个包含 20-30 个链接的 ListProperty(当达到 30 个时,我使用 pop() 将其减少到 20 个),但是!价格相当高...像这里这样的每个 POST 需要 ~200ms,121 cpu_ms,cpm_usd= 0.003588。考虑到我所做的只是将一个字符串保存到列表中,这是非常昂贵的......我认为问题可能是实体随着大 ListProperty 变大了吗?

最佳答案

首先,您担心大量写入 GAE 数据存储是正确的 - 我自己的经验是,与读取相比,它们的开销非常大。例如,我的一个应用程序除了在单个模型表中插入记录外什么都不做,每天写入几万次就用完了免费配额。因此,高效地处理写入会直接转化为您的底线。

第一个问题

我不会将链接存储为单独的实体。数据存储不是 RDBMS,因此标准规范化实践不一定适用。对于每个用户实体,使用 ListProperty 来存储最新的 URL 及其元数据(您可以将所有内容序列化为一个字符串)。

  • 这对于编写来说是高效的,因为您只更新一条记录 - 每当用户添加链接时都不会更新所有链接记录。请记住,要保持滚动列表 (FIFO) 将引用 URL 存储为单独的模型,每个新 URL 都意味着两次写入操作 - 插入新 URL 和删除以删除最旧的 URL。
  • 读取也很高效,因为对用户记录的单次读取可为您提供呈现用户提要所需的所有数据。
  • 从存储的角度来看,世界上的 URL 总数远远超过你的用户数量(即使你成为下一个 Facebook),你的用户选择的 URL 的方差也是如此,所以平均值很可能是URL 将只有一个用户 - 在 RDBMS 样式的数据规范化方面没有真正的 yield 。

另一个优化思路:如果你的用户经常在短时间内添加多个链接,你可以尝试批量编写而不是单独编写。使用内存缓存存储新添加的用户 URL,使用任务队列定期将临时数据写入持久数据存储。我不确定使用任务的资源成本是多少——你必须检查一下。 Here's a good article阅读主题。

第二个问题

使用计数器。请记住,它们在分布式环境中并非微不足道,因此请阅读 - 有许多关于该主题的 GAE 文章、食谱和博客文章 - 只需 google appengine counters .在这里,使用内存缓存也应该是一个不错的选择,以减少数据存储写入的总数。

关于python - GAE 数据存储 - 写入多于读取时的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5603591/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com