我想知道是否有人可以帮我解决这个问题。
我们有一个想要实施的想法,我们目前无法有效地执行此操作。
我尽可能匿名化了数据,但结构是一样的。
我们有两个实体,Car和CarJourney。每辆车都有0到多个CarJourney。每个汽车之旅(以及其他属性)都有与之相关的日期 - 旅程开始的日期。
我想按时间查询汽车旅行。我将有两次,一个开始日期和一个结束日期,其中开始日期< = endDate,我希望收到该期间最近开始的旅程。
所以,如果我有一辆特定的汽车,比如汽车123,我会写一个限制为Car.key和Car.startDate的查询,其中Car.key == 123和Journey.startDate> = startDate和Journey.startDate< = endDate,Journey.startDate的排序下降,限制为1.
e.g。 Car A有3次旅行,分别在1月1日,2日和3日拍摄。查询开始日期为1st,查询结束日期为2nd。这个查询的结果将是一次汽车之旅,第二次。
一旦返回该查询的结果,就会进行非常少量的处理以将结果返回给用户。
这很容易。
但是,我想要一辆汽车列表,而不是超过1辆汽车,列表中包含汽车的N个钥匙。
所以,我想对每辆车运行上述查询N次,一次。我想要每辆车的最新旅程。
因为时间范围很灵活(因此无法事先知道),所以我们无法实现“isMostRecent”标志,因为虽然它现在可能是最新的,但它可能不是最新的。指定的日期参数。
我们还需要确保及时返回(当前查询对于一小组数据大约为3-5秒标记),因为这会直接返回给用户。这意味着我们不能使用任务队列,并且由于指定的日期是任意的,我们无法实现“isWithinDate”字段的质量索引。
我们尝试使用异步查询,但由于处理量可以忽略不计,因此瓶颈仍然是数据存储区上的查询(因为异步api仍然同步发送请求,它只是不会阻塞)。
理想情况下,我们将此作为选择在startDate订购的汽车旅程中,其中Car.key是独特的,但我们似乎无法在GAE中取消这一点。
我们可以进行许多小的优化(例如,重复查询的一些MemCaching),但没有一个在我们的查询时间中产生重大影响。而MemCaching最多只能帮助1-2分钟(由于不可避免的前进时间!)
任何想法都受到欢迎和高度赞赏。
谢谢, 编
答案 0 :(得分:1)
听起来最好的选择是自己执行许多查询。你说你尝试过异步查询,但瓶颈是发送查询。这看起来非常奇怪 - 您应该能够在飞行中同时进行许多查询,从而大大减少延迟。你是怎么决定的?
答案 1 :(得分:0)
首先,我建议使用objectify。关于appengine的JDO / JPA只是让人们误以为appengine数据存储只是一个SQL数据库,正如你所知,这远非事实。
如果我理解正确你有一辆载有CarJourneys列表的汽车?
appengine的列表属性限制为5000个条目,只要您访问/更改它们,就必须整体序列化/反序列化。因此,如果你计划每辆车有很多CarJourneys,那么这将变慢。另外,因为appengine为集合中的每个值创建了一个索引条目,这可能会导致exploding indexes。
相反,只需在CarJourney中创建一个属性汽车,指向行驶的汽车:从CarJourney到Car的一对一关系。类型可以是Key或只包含Car的id的字符串/ long。查询时只需为Car属性添加过滤器。
我建议观看Brett Slatkin的视频:Scalable, Complex Apps on App Engine。
答案 2 :(得分:0)
您还可以使用一个查询并自行过滤不同的汽车。与select CarJouney startDate >= startDate and startDate <= endDate order by startData
类似,并通过此查询迭代(+过滤器),直到找到足够的数据显示。
答案 3 :(得分:0)
非规范化应该可以解决您的问题 - 在您的汽车中拥有last_journey参考属性,因此每次开始旅程时,您都会更新汽车实体 - 这样您就可以查询所有汽车并进行最新的旅程在结果集上。 值得注意的是,当你访问last_journey时,会向数据存储区发出一个新的get(),所以如果你列出了很多汽车,你可以建立一个包含所有last_journey键的列表,然后获取所有的一次,然后通过到db.get()。
Scalable, Complex Apps on App Engine肯定是必须观看的(遗憾的是这个视频的声音太可怕了)
答案 4 :(得分:0)
前段时间我遇到过同样的问题。 我尝试了一些解决方案(在内存排序和 过滤,将事物编码到键等等,我已经对这些进行了基准测试 对于使用100K左右的一些测试数据的延迟和cpu周期 实体) 我采取的另一种方法是将日期编码为整数(日 自年初开始以来的时间或日期开始,同样适用于一天中的小时 或月份取决于您的输出需要多少细节)和 将此保存到属性中。这样就可以转换日期查询过滤器 进入一个只有相等的过滤器,甚至不需要指定一个 index)然后你可以对其他属性进行排序或过滤。 基准测试最新的解决方案我发现过滤时 结果集是未过滤原始集的一小部分,是1+ 数量级更快且cpu-eficient。最糟糕的情况是没有 由于过滤延迟和cpu使用而减少了结果集 与以前的解决方案相当)
希望这会有所帮助,还是我错过了什么?
快乐编码 - :)
答案 5 :(得分:0)
您也可以使用ajax从客户端直接调用此查询。我的意思是你可以向用户返回一个空的html页面,只有汽车定义,然后为此页面上的每辆汽车进行ajax调用。
答案 6 :(得分:-1)
正如JB nizet建议的那样,我想知道答案是否可能是单个查询,可能是临时表或匿名中间表(我不知道谷歌支持这一目的)使用组by(从而消除了额外的数据传输和Java进行处理的需要。
我正在思考一些事情CREATE TEMPORARY TABLE temp1 AS
SELECT * FROM car_journey
WHERE start_date > ? AND
end_date < ?
SELECT car_id, journey_id
FROM temp1 t1, (
SELECT car_id, MIN(start_date)
FROM temp1
GROUP BY car_id
) t2
WHERE t1.car_id = t2.car_id AND
t1.start_date = t2.start_date
使用临时表可以大大减少辅助查询的时间,因为从理论上讲,数据将比完整表小得多。
最后,再次不知道谷歌支持什么,我会问你是否在相应的列上定义了索引,这可能有助于加快查询速度。