我有一个文档集合,其中包含一个主题id、一个时间戳和一个值。例如:
{ sid: 1, t: 3, v: "A" }
{ sid: 1, t: 5, v: "B" }
这意味着subject#1的值在t=3被度量为值A,而在t=5,值被更改为"B“。只有当值被更改时,才会插入新文档。
我的目标是保存更改的历史记录,并允许查询。
我定期地收到另一组包含不同时间的主题和值的文档(t)。然后我需要将这些新信息合并到现有的数据中。假设我收到:
{ sid: 1, t: 2, v: "A" }
{ sid: 1, t: 6, v: "B" }
{ sid: 2, t: 5, v: "C" }
并不是这套新的文件都能给我提供有用的信息。解释:
因此,合并后的结果应该是:
{ sid: 1, t: 2, v: "A" }
{ sid: 1, t: 5, v: "B" }
{ sid: 2, t: 5, v: "C" }
新的信息以流的形式到达,约为2-3k文档/秒。我可以将它作为一个流处理,或者分批处理,15分钟宽=250万个文档。现有的更改--数据收集有数亿个文档。
新到达的数据没有及时排序,它可以包含比现有数据更早或更晚的时间戳。
最简单的方法是查询每个传入文档的现有集合,并查看是否发生了有用的更改,但这意味着每秒对数据存储(Solr)的查询将达到数千次。
另一种方法是以某种方式检测哪些文档可能会受到新数据的影响,并一次性加载、修改并一次性将其写回。我不知道如何才能确定这些文件。**
我试图独立于任何特定技术来问这个问题,因为我认为这个设计问题也与技术栈无关,但是变更数据将存储在Solr中,我可以在Spark中运行聚合。如果能解决这个问题,另一个技术栈建议也是受欢迎的。
如果可以帮助解决这个问题,我还可以更改模式和数据在现有数据和传入数据中的表示方式。
你对这个问题有设计上的建议吗?还是回答我的问题?
发布于 2021-04-24 22:27:21
我想我要指出的是,这里有一些潜在的错误推理。所以,你说如果你有:
{ sid: 1, t: 3, v: "A" }
{ sid: 1, t: 5, v: "B" }
那么{ sid: 1, t: 6, v: "B" }
是多余的。可能是真的。
但是,让我们研究一个例子,当将不更改视为冗余时将是一个错误:
假设我们得到的改变不是在t:6
,而是在t:7
:{ sid: 1, t: 7, v: "B" }
。然后,我们得到了{ sid: 1, t: 6, v: "C" }
。
将这两个示例更改添加到我们的两个原始更改(按时间戳排序):
{ sid: 1, t: 3, v: "A" }
{ sid: 1, t: 5, v: "B" }
{ sid: 1, t: 6, v: "C" }
{ sid: 1, t: 7, v: "B" }
// at t:8 sid:1 is B. This is correct
再次添加这两个更改,但这一次,当它们出现时,让我们删除未更改:
{ sid: 1, t: 3, v: "A" }
{ sid: 1, t: 5, v: "B" }
{ sid: 1, t: 6, v: "C" }
<deleted before event at t:6 was known because it was a non-change from t:5>
// at t:8, sid:1 is C. Whoops. That's wrong.
在当时,t:7
可能看起来是一个多余的不改变,但一旦知道t:6
就变得重要了。如果我们抛弃了t:7
,t:6
就会愚弄我们,以为sid:1
的最终价值是C
。
如果有一个新的变化可以适应的差距,我们就不能对不完整数据的实际冗余做出一个好的决定。
事实上,问题不只是与差距有关。如果您正在接收来自某个源的数据,您不能百分之百地相信它是一致的,您也有一个问题。假设第一个人得到了{ sid: 1, t: 6, v: "C" }
,然后一个人得到了{ sid: 1, t: 6, v: "D" }
。如果第一个被丢弃为“多余”,那么当第二个进入时,就不可能检测到发生了什么奇怪的事情。
你可能已经注意到这是我考虑过的事情。我使用postgresql“时态表”编写了一些代码,类似地配置为不持久化非更新。有意义的代码的一个重要部分是确保严格按照顺序处理事件。
因此,可能只有在查询中或在您维护和更新的读取模型中删除“冗余”数据才有可能从您的更改存储中删除。但这是一个不同的问题,我不知道你的技术或用例如何有效或大规模地做到这一点。
https://softwareengineering.stackexchange.com/questions/425761
复制相似问题