读取许多 JSON 文档并合并在一个(大数据?)
Posted
技术标签:
【中文标题】读取许多 JSON 文档并合并在一个(大数据?)【英文标题】:Read many JSON documents and union in only one (BigData?) 【发布时间】:2016-03-29 19:27:27 【问题描述】:我需要读取许多 JSON 文档并进行合并以仅生成一个文档。
让我解释一下:我有一个跟踪系统来捕获来自网站用户导航的许多事件。我可以使用属性ID来映射相关文档并创建合并文档。
例子
我的意见:
id : "12345", fly : "nyc-bos", time: "10:00am"
id : "12345", fly : "orl-mia", time: "09:00am"
id : "12345", fly : "chi-mem", time: "07:00am"
id : "12345", order: "099300"
id : "12345", order: "677800"
id : "12345", order: "129999"
id : "12345", product: "DVD"
id : "12345", product: "LCD TV"
我需要这样的文件:
id: "12345"
fly :
"nyc-bos", time: "10:00am"
"orl-mia", time: "09:00am"
"chi-mem", time: "07:00am"
order :
"099300"
"677800"
"129999"
product :
"DVD"
"LCD TV"
重要:
我有数百万个输入文档 我无法使用 BigData 框架(Hadoop 等) 我的堆栈受到限制(Windows + C# + CouchDB)有人有我可以遵循的想法吗?
谢谢
【问题讨论】:
【参考方案1】:您只需在 map/reduce 中执行此操作,只需为您的 map 提供一个普通的 emit(doc.id, doc)
,然后为您的 reduce 执行类似的操作:
function( keys, values, rereduce )
var doc = ;
values.forEach( function(d)
var dd = doc[d.id] = doc[d.id] || ;
if(d.fly)
dd['fly'] = dd['fly'] || [];
dd.fly.push( code: d.fly, time: d.time );
else if(d.order)
dd['order'] = dd['order'] || [];
dd.order.push(d.order);
else if(d.product)
dd['product'] = dd['product'] || [];
dd.product.push(d.product);
);
return doc;
请注意,我在fly
对象中使用code
作为键,在JSON 中不能有"nyc-bos", time: "10:00am"
,两个值都需要有键。
【讨论】:
【参考方案2】:您正在查看的是数据聚合,它可以通过 couchdb 使用名为“视图”和“列表”的两个概念来实现。您的技术堆栈应该不是问题,因为从概念上讲,您可以使用 httpclient 与 couchdb 进行交互。我建议你先阅读沙发视图, https://wiki.apache.org/couchdb/Introduction_to_CouchDB_views http://guide.couchdb.org/draft/views.html 一旦你熟悉了它们,你就可以输出一个数据集,如你的第一个 sn-p 中所示,这就是沙发“列表”函数将发挥作用的地方,它可以聚合数据并输出某种格式,如你的第二个 sn-p .基本上,列表函数位于管道中的视图函数旁边,它们将被提供视图函数的输出。通过阅读官方 couchdb 文档,您可以更深入地理解这个概念。为方便起见,请参阅下面的链接。 http://guide.couchdb.org/draft/transforming.html
如果需要为文档输出一个统计数据集 (couch reduce functions),它可能看起来像这样
"rows":
[
"key":"de", "value":"sum":2,"count":2,"min":1,"max":1,"sumsqr":2,
"key":"ee", "value":"sum":2,"count":2,"min":1,"max":1,"sumsqr":2,
"key":"de", "value":"sum":2,"count":2,"min":1,"max":1,"sumsqr":2,
"key":"ee", "value":"sum":2,"count":2,"min":1,"max":1,"sumsqr":2,
"key":"de", "value":"sum":2,"count":2,"min":1,"max":1,"sumsqr":2
]
为了聚合它们,我们可以输出一个具有唯一键但聚合值(最小值、最大值等)的数据集,我们可以编写一个列表函数,如下所示
function(head, req)
var row;
var result = [];
var firstRun = true;
var found = true;
start(
"headers":
"Content-Type": "application/json"
);
while(row = getRow())
if(firstRun)
firstRun = false;
result.push(id: row.key, sum: row.value.sum, count: row.value.count, min: row.value.min, max: row.value.max, sumsqr: row.value.sumsqr);
else
for (var i = 0; i < result.length; i++)
if (row.key === result[i].id)
result[i].sum += row.value.sum;
result[i].count += row.value.count;
result[i].min = ((row.value.min < result[i].min) ? row.value.min : result[i].min);
result[i].max = ((row.value.max > result[i].max) ? row.value.max : result[i].max);
result[i].sumsqr = result[i].sum;
found = true;
break;
else
found = false;
if(!found)
result.push(id: row.key, sum: row.value.sum, count: row.value.count, min: row.value.min, max: row.value.max, sumsqr: row.value.sumsqr);
found = true;
return JSON.stringify(result);
【讨论】:
【参考方案3】:这是Map/Reduce "collation" 的典型案例。
注意:由于id
具有误导性(带有_id
,文档标识符),我将其称为user_id
。
首先,您必须发出没有值的排序规则键(永远不要发出 doc
作为值。索引越轻越好。到原始文档的链接会自动完成)。我们还将类别添加到键中,因为您希望对结果进行排序。
function(o)
if (o.fly)
emit([o.user_id, 'fly']);
else if (o.order)
emit([o.user_id, 'order']);
else if (o.product)
emit([o.user_id, 'product']);
不要定义 reduce 函数,因为您想保留指向原始文档的链接。
使用include_docs=true
查询您的视图以获取链接的文档并使用startkey
和endkey
选择用户:
/mydb/_design/mydesign/_view/myview?include_docs=true&startkey=["12345"]&endkey=["12345",]
你会得到:
[
"key":["12345", "fly"], "value": null, "doc":"user_id": "12345", "fly":"nyc-bos", "time":"10:00am",
"key":["12345", "fly"], "value": null, "doc":"user_id": "12345", "fly": "orl-mia", "time": "09:00am",
"key":["12345", "fly"], "value": null, "doc":"user_id": "12345", "fly": "chi-mem", "time": "07:00am",
"key":["12345", "order"], "value": null, "doc":"user_id": "12345", "order": "099300",
"key":["12345", "order"], "value": null, "doc":"user_id": "12345", "order": "677800",
"key":["12345", "order"], "value": null, "doc":"user_id": "12345", "order": "129999",
"key":["12345", "product"], "value": null, "doc":"user_id": "12345", "product": "DVD",
"key":["12345", "product"], "value": null, "doc":"user_id": "12345", "product": "LCD TV"
]
所有繁重的计算(也称为“限制”、“连接”和“排序”)都由 Map/Reduce 完成。然后,您可以使用简单的list function 调整格式。
【讨论】:
以上是关于读取许多 JSON 文档并合并在一个(大数据?)的主要内容,如果未能解决你的问题,请参考以下文章
如何读取真正大的 JSON 文件并使用 node.js 将该文件的数据插入 MYSQL 数据库?