Skip to content

Commit 97b46f2

Browse files
author
Anil Maurya
committed
Add support for file streaming
1 parent 7005410 commit 97b46f2

File tree

10 files changed

+73400
-14211
lines changed

10 files changed

+73400
-14211
lines changed

Gemfile.lock

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
fast_jsonparser (0.1.0)
4+
fast_jsonparser (0.2.0)
55

66
GEM
77
remote: https://rubygems.org/
@@ -11,6 +11,7 @@ GEM
1111
rake (13.0.1)
1212
rake-compiler (1.1.0)
1313
rake
14+
yajl-ruby (1.4.1)
1415

1516
PLATFORMS
1617
ruby
@@ -22,6 +23,7 @@ DEPENDENCIES
2223
oj
2324
rake (~> 13.0)
2425
rake-compiler
26+
yajl-ruby
2527

2628
BUNDLED WITH
2729
2.0.1

README.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,17 @@ FastJsonparser.parse(json) is 96% faster than JSON.parse(json)
3838
# standard JSON 13.025884 0.031287 13.057171 ( 13.264931) ~ 96% more
3939
```
4040

41+
3. Streaming json from file
42+
```
43+
FastJsonparser.load_many(src) is 153% faster than Yajl::Parser.new.parse(File.new(src, 'r'))
44+
```
45+
[Benchmark result](https://github.com/anilmaurya/fast_jsonparser/blob/master/benchmark/stream_benchmark.rb)
46+
```
47+
# user system total real
48+
# FastJsonparser 3.844446 0.141822 3.986268 ( 3.884655)
49+
# YAJL 9.699621 0.110060 9.809681 ( 9.826104) ~ 150% more
50+
```
51+
4152
## Installation
4253

4354
Add this line to your application's Gemfile:
@@ -78,7 +89,27 @@ FastJsonparser.parse('{"one": 1, "two": 2}')
7889
7990
```
8091

81-
3. Raise FastJsonparser::ParseError when invalid JSON provided for parsing
92+
3. Streaming JSON from file
93+
94+
File with multiple json can be stream with `load_many` method
95+
96+
Example: logs.json with following content
97+
```
98+
{"time": "17/May/2015:08:05:32 +0000", "remote_ip": "93.180.71.3", "remote_user": "-"}
99+
{"time": "17/May/2015:08:05:23 +0000", "remote_ip": "93.180.71.3", "remote_user": "-"}
100+
{"time": "17/May/2015:08:05:24 +0000", "remote_ip": "80.91.33.133", "remote_user": "-"}
101+
```
102+
103+
`load_many` accepts file_path & block as arguments
104+
```
105+
> FastJsonparser.load_many(file_path) { |obj| p obj[:time]}
106+
"17/May/2015:08:05:32 +0000"
107+
"17/May/2015:08:05:23 +0000"
108+
"17/May/2015:08:05:24 +0000"
109+
```
110+
111+
112+
4. Raise FastJsonparser::ParseError when invalid JSON provided for parsing
82113

83114
```
84115
FastJsonparser.parse("123: 1") # FastJsonparser::ParseError (parse error)

benchmark/nginx_json_logs.json

Lines changed: 51462 additions & 0 deletions
Large diffs are not rendered by default.

benchmark/stream_benchmark.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/usr/bin/env ruby
2+
3+
require 'benchmark'
4+
require 'json'
5+
require './lib/fast_jsonparser/fast_jsonparser'
6+
require 'yajl'
7+
8+
def run_report(rep, src)
9+
n = 30
10+
rep.report("FastJsonparser") do
11+
n.times do
12+
FastJsonparser.load_many(src) {}
13+
end
14+
end
15+
rep.report("YAJL") do
16+
n.times do
17+
parser = Yajl::Parser.new
18+
parser.parse(File.new(src, 'r')) {}
19+
end
20+
end
21+
end
22+
23+
Benchmark.bm do |rep|
24+
run_report(rep, './benchmark/nginx_json_logs.json')
25+
end
26+
27+
28+
# nginx_json_logs.json 12M
29+
# user system total real
30+
# FastJsonparser 3.844446 0.141822 3.986268 ( 3.884655)
31+
# YAJL 9.699621 0.110060 9.809681 ( 9.826104) ~ 150% more

ext/fast_jsonparser/fast_jsonparser.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,27 @@ static VALUE rb_fast_jsonparser_load(VALUE self, VALUE arg)
9393
return Qnil;
9494
}
9595

96+
static VALUE rb_fast_jsonparser_load_many(VALUE self, VALUE arg)
97+
{
98+
Check_Type(arg, T_STRING);
99+
100+
dom::parser parser;
101+
auto [docs, error] = parser.load_many(RSTRING_PTR(arg));
102+
if (error == SUCCESS)
103+
{
104+
for (dom::element doc : docs)
105+
{
106+
if (rb_block_given_p())
107+
{
108+
rb_yield(make_ruby_object(doc));
109+
}
110+
}
111+
return Qnil;
112+
}
113+
rb_raise(rb_eFastJsonparserParseError, "parse error");
114+
return Qnil;
115+
}
116+
96117
extern "C"
97118
{
98119

@@ -102,5 +123,6 @@ extern "C"
102123
rb_eFastJsonparserParseError = rb_define_class_under(rb_mFastJsonparser, "ParseError", rb_eStandardError);
103124
rb_define_module_function(rb_mFastJsonparser, "parse", reinterpret_cast<VALUE (*)(...)>(rb_fast_jsonparser_parse), 1);
104125
rb_define_module_function(rb_mFastJsonparser, "load", reinterpret_cast<VALUE (*)(...)>(rb_fast_jsonparser_load), 1);
126+
rb_define_module_function(rb_mFastJsonparser, "load_many", reinterpret_cast<VALUE (*)(...)>(rb_fast_jsonparser_load_many), 1);
105127
}
106128
}

0 commit comments

Comments
 (0)