查找datastore中是否存在大量key(最多1M)
Lookup the existence of a large number of keys (up to1M) in datastore
我们有一个 table 在 google 云数据存储中有 100M 行。查找大量键(500K-1M)是否存在最有效的方法是什么?
就上下文而言,一个用例可能是我们拥有一个大型内容数据存储区(想想一个域中的所有网页)。此数据存储包含每个文档的预爬网内容和元数据。然而,每个文档都可能被许多用户喜欢。现在,当我们有一个新用户并且 he/she 说 he/she 喜欢文档 {a1, a2, ..., an}
时,我们想知道是否所有这些文档 ak {k in 1 to n}
都已被抓取。这就是我们要进行上述查找的原因。如果有我们还没有的文档子集,我们会立即开始抓取它们。是的,最终目标是检索所有这些文档内容并使用它们来构建用户配置文件。
我目前的想法是发出一堆 batch 查找请求。每个查找请求最多可以包含 1K 的键 [1]。但是要获得一组 1M 中每个键的存在,我仍然需要发出 1000 个请求。
另一种方法是使用自定义的中间层来提供快速查找(例如,可以使用布隆过滤器或类似的东西)以节省多个请求之间的时间。假设我们从不删除键,每次插入键时,我们都会通过中间层添加它。 bloom-filter 跟踪我们拥有的密钥(具有可容忍的误报率)。由于这是一个自定义层,我们可以无限制地提供微服务。假设我们可以响应请求是否存在 1M 密钥的请求。但是,这肯定会增加我们的 design/implementation 复杂性。
有没有更有效的方法来做到这一点?也许更好的设计?谢谢!
我建议使用更具可扩展性(且成本更低)的方法来解决问题。
在您提到的用例中,您一次可以处理一个文档,每个文档在数据存储区中都有一个对应的实体。
网页 URL 唯一标识页面,因此您可以使用它为相应的实体生成唯一的 key/identifier。通过单键查找(强一致性),您可以确定实体是否存在,即网页是否已被考虑用于抓取。如果还没有,则会创建一个新实体并为其启动爬网作业。
实体键的长度可能是个问题,请参阅 How long (max characters) can a datastore entity key_name be? Is it bad to haver very long key_names?. To avoid it you can have the URL stored as a property of the webpage entity. You'll then have to query for the entity by the url property to determine if the webpage has already been considered for crawling. This is just eventually consistent,这意味着从创建文档实体(及其抓取作业启动)到它出现在查询中可能需要一段时间结果。没什么大不了的,可以通过抓取作业中的一些逻辑来解决,以防止and/or删除文档重复项。
我会将 "like" 信息作为将文档映射到用户的小实体,与文档和用户实体分开,以防止在单个实体中维护可能非常长的列表的缺点,参见 and 。
当用户喜欢具有特定 URL 的网页时,您只需检查匹配的文档实体是否存在:
- 如果它只是创建类似的映射实体
- 如果没有并且您使用了上述唯一密钥标识符:
- 创建文档实体并启动其爬网作业
- 创建类似的映射实体
- 否则:
- 启动创建文档实体的爬网作业,负责去重
- 稍后(唯一)文档实体可用时,启动延迟作业以创建映射实体。可能链接了爬行作业。可能需要一些重试逻辑。
检查用户是否喜欢特定文档变成了对此类映射实体的简单查询(需要小心,因为它最终也是一致的)。
有了这样的方案,您不再需要进行那些大量的查找,您一次只做一个 - 没关系,恕我直言,用户一次只喜欢一个文档比提供一大堆喜欢的文档更自然文档。
我们有一个 table 在 google 云数据存储中有 100M 行。查找大量键(500K-1M)是否存在最有效的方法是什么?
就上下文而言,一个用例可能是我们拥有一个大型内容数据存储区(想想一个域中的所有网页)。此数据存储包含每个文档的预爬网内容和元数据。然而,每个文档都可能被许多用户喜欢。现在,当我们有一个新用户并且 he/she 说 he/she 喜欢文档 {a1, a2, ..., an}
时,我们想知道是否所有这些文档 ak {k in 1 to n}
都已被抓取。这就是我们要进行上述查找的原因。如果有我们还没有的文档子集,我们会立即开始抓取它们。是的,最终目标是检索所有这些文档内容并使用它们来构建用户配置文件。
我目前的想法是发出一堆 batch 查找请求。每个查找请求最多可以包含 1K 的键 [1]。但是要获得一组 1M 中每个键的存在,我仍然需要发出 1000 个请求。
另一种方法是使用自定义的中间层来提供快速查找(例如,可以使用布隆过滤器或类似的东西)以节省多个请求之间的时间。假设我们从不删除键,每次插入键时,我们都会通过中间层添加它。 bloom-filter 跟踪我们拥有的密钥(具有可容忍的误报率)。由于这是一个自定义层,我们可以无限制地提供微服务。假设我们可以响应请求是否存在 1M 密钥的请求。但是,这肯定会增加我们的 design/implementation 复杂性。
有没有更有效的方法来做到这一点?也许更好的设计?谢谢!
我建议使用更具可扩展性(且成本更低)的方法来解决问题。
在您提到的用例中,您一次可以处理一个文档,每个文档在数据存储区中都有一个对应的实体。 网页 URL 唯一标识页面,因此您可以使用它为相应的实体生成唯一的 key/identifier。通过单键查找(强一致性),您可以确定实体是否存在,即网页是否已被考虑用于抓取。如果还没有,则会创建一个新实体并为其启动爬网作业。
实体键的长度可能是个问题,请参阅 How long (max characters) can a datastore entity key_name be? Is it bad to haver very long key_names?. To avoid it you can have the URL stored as a property of the webpage entity. You'll then have to query for the entity by the url property to determine if the webpage has already been considered for crawling. This is just eventually consistent,这意味着从创建文档实体(及其抓取作业启动)到它出现在查询中可能需要一段时间结果。没什么大不了的,可以通过抓取作业中的一些逻辑来解决,以防止and/or删除文档重复项。
我会将 "like" 信息作为将文档映射到用户的小实体,与文档和用户实体分开,以防止在单个实体中维护可能非常长的列表的缺点,参见
当用户喜欢具有特定 URL 的网页时,您只需检查匹配的文档实体是否存在:
- 如果它只是创建类似的映射实体
- 如果没有并且您使用了上述唯一密钥标识符:
- 创建文档实体并启动其爬网作业
- 创建类似的映射实体
- 否则:
- 启动创建文档实体的爬网作业,负责去重
- 稍后(唯一)文档实体可用时,启动延迟作业以创建映射实体。可能链接了爬行作业。可能需要一些重试逻辑。
检查用户是否喜欢特定文档变成了对此类映射实体的简单查询(需要小心,因为它最终也是一致的)。
有了这样的方案,您不再需要进行那些大量的查找,您一次只做一个 - 没关系,恕我直言,用户一次只喜欢一个文档比提供一大堆喜欢的文档更自然文档。