使用jq处理巨大的GEOJson文件
给定一个GEOJson文件,如下所示:-使用jq处理巨大的GEOJson文件,json,stream,geojson,jq,bigdata,Json,Stream,Geojson,Jq,Bigdata,给定一个GEOJson文件,如下所示:- { "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": { "FEATCODE": 15014 }, "geometry": { "type": "Polygon", "coordinates": [ ..... 我想以以下内容结束:- { "type": "Featu
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"FEATCODE": 15014
},
"geometry": {
"type": "Polygon",
"coordinates": [
.....
我想以以下内容结束:-
{
"type": "FeatureCollection",
"features": [
{
"tippecanoe : {"minzoom" : 13},
"type": "Feature",
"properties": {
"FEATCODE": 15014
},
"geometry": {
"type": "Polygon",
"coordinates": [
.....
即,我已将TipperCanoe对象添加到数组功能中的每个功能中
我可以通过以下方式实现这一点:-
jq '.features[].tippecanoe.minzoom = 13' <GEOJSON FILE> > <OUTPUT FILE>
jq'.features[].tippecanoe.minzoom=13'>
这对于小文件来说很好。但是处理一个414Mb的大文件似乎要花费很长时间,因为处理器已经达到最大值,并且输出文件中没有写入任何内容
进一步阅读jq,似乎--stream命令行参数可能会有所帮助,但我完全搞不清楚如何将其用于我的目的
如果能提供一个示例命令行,并解释--stream正在做什么,我将不胜感激。另一种解决方案可以是:
jq '.features |= map_values(.tippecanoe.minzoom = 13)'
为了测试这一点,我创建了一个示例JSON作为
d = {'features': [{"type":"Feature", "properties":{"FEATCODE": 15014}} for i in range(0,N)]}
并根据N
检查执行时间。有趣的是,虽然map_值
方法在N
中似乎具有线性复杂性,.features[].tippecanoe.minzoom=13
表现出二次行为(对于N=50000,前一种方法大约在0.8秒内完成,而后一种方法大约需要47秒)
或者,您也可以使用Python手动执行此操作:
import json
import sys
data = {}
with open(sys.argv[1], 'r') as F:
data = json.load(F)
extra_item = {"minzoom" : 13}
for feature in data['features']:
feature["tippecanoe"] = extra_item
with open(sys.argv[2], 'w') as F:
F.write(json.dumps(data))
在这种情况下,
map
比map\u值快得多(*):
然而,使用这种方法仍然需要足够的RAM
p、 如果您想使用jq生成一个大文件进行计时,请考虑:
def N: 1000000;
def data:
{"features": [range(0;N) | {"type":"Feature", "properties": {"FEATCODE": 15014}}] };
(*)使用map
,100MB为20s,近似线性。单通道jq方法可能需要比可用内存更多的RAM。如果是这种情况,那么下面将显示一种简单的全jq方法,以及一种基于jq和awk的更经济的方法
这两种方法是相同的,只是将对象流重新构造为单个JSON文档。使用awk可以非常经济地完成此步骤
在这两种情况下,假定包含所需形式对象的大型JSON输入文件名为input.JSON
仅限jq
jq和awk
性能比较
为了进行比较,使用了在.features[]中包含10000000个对象的输入文件。它的大小约为1GB
u+s:
这里,基于GitHub的@nicowilliams的工作,是一个使用jq提供的流式解析器的解决方案。该解决方案在内存方面非常经济,但如果输入较大,则当前速度相当慢
该解决方案有两部分:一个用于将更新注入到使用--stream命令行选项生成的流中的函数;以及一个用于将流转换回原始格式的JSON的函数
调用:
program.jq
测试数据的生成
示例输出
N=2时:
[
{"type":"Feature","properties":{"FEATCODE":15014},"tippecanoe":{"minzoom":13}}
,
{"type":"Feature","properties":{"FEATCODE":15014},"tippecanoe":{"minzoom":13}}
]
在我的600k功能文件中仍然需要很长时间。我不得不求助于一些可怕的东西,比如塞德的#“属性”#“蒂普卡诺”:{“minzoom”:13},“属性”#g'@CitizenFish在这种情况下,我倾向于更健壮的东西,例如Python——我用一个例子更新了答案(对于这个特定的情况,它似乎要快得多)…谢谢,但它并没有真正回答我的问题,而我的问题是针对--stream的。python脚本似乎一次就加载了json,我怀疑这会导致大文件的问题/分页。我的一些是>5Gbah的,事实上,那么可能会更相关。。。
jq -c '.features[]' input.json |
jq -c '.tippecanoe.minzoom = 13' |
jq -c -s '{type: "FeatureCollection", features: .}'
jq -c '.features[]' input.json |
jq -c '.tippecanoe.minzoom = 13' | awk '
BEGIN {print "{\"type\": \"FeatureCollection\", \"features\": ["; }
NR==1 { print; next }
{print ","; print}
END {print "] }";}'
jq-only: 15m 15s
jq-awk: 7m 40s
jq one-pass using map: 6m 53s
jq -cnr --stream -f program.jq input.json
# inject the given object into the stream produced from "inputs" with the --stream option
def inject(object):
[object|tostream] as $object
| 2
| truncate_stream(inputs)
| if (.[0]|length == 1) and length == 1
then $object[]
else .
end ;
# Input: the object to be added
# Output: text
def output:
. as $object
| ( "[",
foreach fromstream( inject($object) ) as $o
(0;
if .==0 then 1 else 2 end;
if .==1 then $o else ",", $o end),
"]" ) ;
{}
| .tippecanoe.minzoom = 13
| output
def data(N):
{"features":
[range(0;2) | {"type":"Feature", "properties": {"FEATCODE": 15014}}] };
[
{"type":"Feature","properties":{"FEATCODE":15014},"tippecanoe":{"minzoom":13}}
,
{"type":"Feature","properties":{"FEATCODE":15014},"tippecanoe":{"minzoom":13}}
]