tem_mr_search 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +1 -0
- data/LICENSE +21 -0
- data/Manifest +25 -0
- data/README +4 -0
- data/Rakefile +23 -0
- data/lib/tem_mr_search/client_query.rb +21 -0
- data/lib/tem_mr_search/db.rb +19 -0
- data/lib/tem_mr_search/map_reduce_executor.rb +114 -0
- data/lib/tem_mr_search/map_reduce_job.rb +67 -0
- data/lib/tem_mr_search/map_reduce_planner.rb +169 -0
- data/lib/tem_mr_search/query_builder.rb +167 -0
- data/lib/tem_mr_search.rb +17 -0
- data/tem_mr_search.gemspec +37 -0
- data/test/mr_test_case.rb +58 -0
- data/test/test_db.rb +10 -0
- data/test/test_map_reduce_executor.rb +37 -0
- data/test/test_map_reduce_job.rb +45 -0
- data/test/test_map_reduce_planner.rb +55 -0
- data/test/test_query_builder.rb +40 -0
- data/testdata/fares.yml +49 -0
- data/testdata/parallel_plan_431.yml +52 -0
- data/testdata/parallel_plan_740.yml +87 -0
- data/testdata/serial_plan_410.yml +36 -0
- data/testdata/serial_plan_431.yml +56 -0
- data/testdata/serial_plan_740.yml +93 -0
- metadata +116 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'tem_mr_search'
|
3
|
+
|
4
|
+
class MrTestCase < Test::Unit::TestCase
|
5
|
+
include Tem::Mr::Search
|
6
|
+
|
7
|
+
def setup
|
8
|
+
super
|
9
|
+
|
10
|
+
Thread.abort_on_exception = true
|
11
|
+
|
12
|
+
testdb_path = File.join File.dirname(__FILE__), "..", "testdata",
|
13
|
+
"fares.yml"
|
14
|
+
@db = Db.new testdb_path
|
15
|
+
|
16
|
+
@client_query = QueryBuilder.query { |q|
|
17
|
+
q.attributes :price => :tem_short, :start => :tem_short,
|
18
|
+
:end => :tem_short
|
19
|
+
q.id_attribute :flight
|
20
|
+
|
21
|
+
# Score: 200 + start / 100 - duration - price
|
22
|
+
q.map { |s|
|
23
|
+
s.ldwc 200
|
24
|
+
s.ldw :start
|
25
|
+
s.ldbc 100
|
26
|
+
s.div
|
27
|
+
s.add
|
28
|
+
s.ldw :end
|
29
|
+
s.ldw :start
|
30
|
+
s.sub
|
31
|
+
s.sub
|
32
|
+
s.ldw :price
|
33
|
+
s.sub
|
34
|
+
s.stw :score
|
35
|
+
}
|
36
|
+
|
37
|
+
# The greater score wins.
|
38
|
+
q.reduce { |s|
|
39
|
+
s.ldw :score1
|
40
|
+
s.ldw :score2
|
41
|
+
s.cmp
|
42
|
+
s.stw :comparison
|
43
|
+
}
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def fare_score(fare)
|
48
|
+
200 + fare['start'] / 100 - fare['price'] - (fare['end'] - fare['start'])
|
49
|
+
end
|
50
|
+
|
51
|
+
def fare_id(fare)
|
52
|
+
fare['flight']
|
53
|
+
end
|
54
|
+
|
55
|
+
# Ensures that everything has loaded.
|
56
|
+
def test_smoke
|
57
|
+
end
|
58
|
+
end
|
data/test/test_db.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'test/mr_test_case'
|
2
|
+
|
3
|
+
class DbTest < MrTestCase
|
4
|
+
def test_loading
|
5
|
+
assert_equal 4, @db.length, 'Number of items in the database'
|
6
|
+
gold_item = {'from' => 'BOS', 'to' => 'NYC', 'price' => 150, 'start' => 900,
|
7
|
+
'end' => 1000, 'flight' => 15 }
|
8
|
+
assert_equal gold_item, @db.item(0), 'First database item'
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'test/mr_test_case'
|
2
|
+
|
3
|
+
class MapReduceExecutorTest < MrTestCase
|
4
|
+
MRExecutor = Tem::Mr::Search::MapReduceExecutor
|
5
|
+
|
6
|
+
def setup
|
7
|
+
super
|
8
|
+
Tem.auto_conf
|
9
|
+
$tem.activate
|
10
|
+
$tem.emit
|
11
|
+
end
|
12
|
+
|
13
|
+
def _test_executor(tems, root_tem)
|
14
|
+
executor = MRExecutor.new @client_query, @db, tems, root_tem
|
15
|
+
packed_output = executor.execute
|
16
|
+
result = @client_query.unpack_output packed_output
|
17
|
+
assert_equal 18, result[:id], 'Incorrect Map-Reduce result'
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_executor_with_autoconf
|
21
|
+
_test_executor [$tem], 0
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_executor_with_cluster
|
25
|
+
cluster_config = ['lightbulb2.local', 'darkbulb.local'].map { |host|
|
26
|
+
Tem::MultiProxy::Client.query_tems host
|
27
|
+
}.flatten
|
28
|
+
assert_equal 8, cluster_config.length, 'Incorrect cluster setup'
|
29
|
+
tems = cluster_config.map do |config|
|
30
|
+
Tem::Session.new Tem::Transport::AutoConfigurator.try_transport(config)
|
31
|
+
end
|
32
|
+
|
33
|
+
tems.each { |tem| tem.activate; tem.emit }
|
34
|
+
|
35
|
+
_test_executor tems, 0
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'test/mr_test_case'
|
2
|
+
|
3
|
+
class MapReduceJobTest < MrTestCase
|
4
|
+
def setup
|
5
|
+
super
|
6
|
+
|
7
|
+
@obj1 = @db.item 0
|
8
|
+
@obj2 = @db.item 1
|
9
|
+
@output1 = (1..16).to_a
|
10
|
+
@output2 = (17..32).to_a
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_map_for_object
|
14
|
+
obj = @obj1.merge 'flight' => 0x12345678
|
15
|
+
secpack = @client_query.map_for_object obj
|
16
|
+
|
17
|
+
assert_equal [0, 0, 0, 0, 0x12, 0x34, 0x56, 0x78],
|
18
|
+
secpack.get_bytes(:_id, 8), 'Object ID embedded incorrectly'
|
19
|
+
assert_equal @obj1['price'], secpack.get_value(:price, :tem_short),
|
20
|
+
'Price embedded incorrectly'
|
21
|
+
assert_equal @obj1['start'], secpack.get_value(:start, :tem_short),
|
22
|
+
'Starting time embedded incorrectly'
|
23
|
+
assert_equal @obj1['end'], secpack.get_value(:end, :tem_short),
|
24
|
+
'Ending time embedded incorrectly'
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_reduce_for_outputs
|
28
|
+
secpack = @client_query.reduce_for_outputs @output1, @output2
|
29
|
+
|
30
|
+
assert_equal @output1, secpack.get_bytes(:_output1, 16),
|
31
|
+
'Output1 embedded incorrectly'
|
32
|
+
assert_equal @output2, secpack.get_bytes(:_output2, 16),
|
33
|
+
'Output2 embedded incorrectly'
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_unpack_unencrypted_output
|
37
|
+
packed_output = [0, 0, 0, 0, 0x12, 0x34, 0x56, 0x78, 0x31, 0x41, 0xCC, 0xCD,
|
38
|
+
0xCE, 0xBE, 0xEF, 0xFE]
|
39
|
+
output = @client_query.unpack_decrypted_output packed_output
|
40
|
+
|
41
|
+
assert_equal 0x12345678, output[:id], 'ID incorrectly unpacked'
|
42
|
+
assert_equal 0x3141, output[:score], 'Score incorrectly unpacked'
|
43
|
+
assert_equal [0xBE, 0xEF, 0xFE], output[:check], 'Check bytes'
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'test/mr_test_case'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
class MapReducePlannerTest < Test::Unit::TestCase
|
5
|
+
MRPlanner = Tem::Mr::Search::MapReducePlanner
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@testdata_path = File.join(File.dirname(__FILE__), '..', 'testdata')
|
9
|
+
end
|
10
|
+
|
11
|
+
def parallel_planning(planner)
|
12
|
+
all_actions = []
|
13
|
+
until planner.done?
|
14
|
+
actions = planner.next_actions!
|
15
|
+
all_actions << actions
|
16
|
+
actions.each { |action| planner.action_done action }
|
17
|
+
end
|
18
|
+
all_actions
|
19
|
+
end
|
20
|
+
|
21
|
+
def serial_planning(planner)
|
22
|
+
all_actions = []
|
23
|
+
pending_actions = []
|
24
|
+
until planner.done?
|
25
|
+
actions = planner.next_actions!
|
26
|
+
all_actions << actions
|
27
|
+
pending_actions += actions
|
28
|
+
action = pending_actions.shift
|
29
|
+
planner.action_done action if action
|
30
|
+
end
|
31
|
+
all_actions
|
32
|
+
end
|
33
|
+
|
34
|
+
def _test_planning(method_name, items, tems, root_tem, gold_file)
|
35
|
+
planner = MRPlanner.new nil, items, tems, root_tem
|
36
|
+
all_actions = self.send method_name, planner
|
37
|
+
gold_actions = File.open(File.join(@testdata_path, gold_file), 'r') do |f|
|
38
|
+
YAML.load f
|
39
|
+
end
|
40
|
+
assert_equal gold_actions, all_actions, "Failed #{method_name}: " +
|
41
|
+
"#{tems} tems with root #{root_tem}, #{items} items"
|
42
|
+
assert_equal items * 2 - 1, planner.output_id, "Wrong final output_id"
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_planning
|
46
|
+
[[:parallel_planning, 7, 4, 0, 'parallel_plan_740.yml'],
|
47
|
+
[:parallel_planning, 4, 3, 1, 'parallel_plan_431.yml'],
|
48
|
+
[:serial_planning, 4, 1, 0, 'serial_plan_410.yml'],
|
49
|
+
[:serial_planning, 7, 4, 0, 'serial_plan_740.yml'],
|
50
|
+
[:serial_planning, 4, 3, 1, 'serial_plan_431.yml'],
|
51
|
+
].each do |testcase|
|
52
|
+
_test_planning *testcase
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'test/mr_test_case'
|
2
|
+
|
3
|
+
class QueryBuilderTest < MrTestCase
|
4
|
+
def setup
|
5
|
+
super
|
6
|
+
Tem.auto_conf
|
7
|
+
$tem.activate
|
8
|
+
$tem.emit
|
9
|
+
end
|
10
|
+
|
11
|
+
def _test_map_fare(fare)
|
12
|
+
enc_output = @client_query.map_object fare, $tem
|
13
|
+
output = @client_query.unpack_output enc_output
|
14
|
+
assert_equal fare_id(fare), output[:id], 'Object ID incorrectly encoded'
|
15
|
+
assert_equal fare_score(fare), output[:score],
|
16
|
+
'Score incorrectly computed'
|
17
|
+
enc_output
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_map_reduce
|
21
|
+
fare1 = @db.item 0
|
22
|
+
output1 = _test_map_fare fare1
|
23
|
+
fare2 = @db.item 1
|
24
|
+
output2 = _test_map_fare fare2
|
25
|
+
|
26
|
+
win_fare = (fare_score(fare1) > fare_score(fare2)) ? fare1 : fare2
|
27
|
+
# Try both permutations to ensure all branches of the reduce code work.
|
28
|
+
[[output1, output2], [output2, output1]].each do |o1, o2|
|
29
|
+
enc_output = @client_query.reduce_outputs o1, o2, $tem
|
30
|
+
output = @client_query.unpack_output enc_output
|
31
|
+
assert_equal fare_id(win_fare), output[:id], 'The wrong fare won (bad ID)'
|
32
|
+
assert_equal fare_score(win_fare), output[:score],
|
33
|
+
'The wrong fare won (bad score)'
|
34
|
+
assert_equal [1, 2, 3], output[:check], 'Incorrect check bytes'
|
35
|
+
|
36
|
+
assert_not_equal enc_output, output1, 'Nonce fail'
|
37
|
+
assert_not_equal enc_output, output2, 'Nonce fail'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/testdata/fares.yml
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
---
|
2
|
+
- from: BOS
|
3
|
+
to: NYC
|
4
|
+
price: 150
|
5
|
+
start: 900
|
6
|
+
end: 1000
|
7
|
+
flight: 15
|
8
|
+
- from: BOS
|
9
|
+
to: NYC
|
10
|
+
price: 150
|
11
|
+
start: 1800
|
12
|
+
end: 1900
|
13
|
+
flight: 16
|
14
|
+
- from: BOS
|
15
|
+
to: NYC
|
16
|
+
price: 200
|
17
|
+
start: 1200
|
18
|
+
end: 1245
|
19
|
+
flight: 17
|
20
|
+
- from: BOS
|
21
|
+
to: NYC
|
22
|
+
price: 200
|
23
|
+
start: 1700
|
24
|
+
end: 1745
|
25
|
+
flight: 18
|
26
|
+
- from: BOS
|
27
|
+
to: NYC
|
28
|
+
price: 160
|
29
|
+
start: 900
|
30
|
+
end: 1000
|
31
|
+
flight: 21
|
32
|
+
- from: BOS
|
33
|
+
to: NYC
|
34
|
+
price: 160
|
35
|
+
start: 1800
|
36
|
+
end: 1900
|
37
|
+
flight: 22
|
38
|
+
- from: BOS
|
39
|
+
to: NYC
|
40
|
+
price: 210
|
41
|
+
start: 1200
|
42
|
+
end: 1245
|
43
|
+
flight: 23
|
44
|
+
- from: BOS
|
45
|
+
to: NYC
|
46
|
+
price: 210
|
47
|
+
start: 1700
|
48
|
+
end: 1745
|
49
|
+
flight: 24
|
@@ -0,0 +1,52 @@
|
|
1
|
+
---
|
2
|
+
- - :secpack: :mapper
|
3
|
+
:action: :migrate
|
4
|
+
:with: 1
|
5
|
+
:to: 0
|
6
|
+
- - :secpack: :mapper
|
7
|
+
:action: :migrate
|
8
|
+
:with: 0
|
9
|
+
:to: 2
|
10
|
+
- :secpack: :reducer
|
11
|
+
:action: :migrate
|
12
|
+
:with: 1
|
13
|
+
:to: 0
|
14
|
+
- - :secpack: :reducer
|
15
|
+
:action: :migrate
|
16
|
+
:with: 0
|
17
|
+
:to: 2
|
18
|
+
- :output_id: 0
|
19
|
+
:action: :map
|
20
|
+
:with: 1
|
21
|
+
:item: 0
|
22
|
+
- :output_id: 1
|
23
|
+
:action: :map
|
24
|
+
:with: 2
|
25
|
+
:item: 1
|
26
|
+
- - :output_id: 2
|
27
|
+
:action: :map
|
28
|
+
:with: 0
|
29
|
+
:item: 2
|
30
|
+
- :output_id: 3
|
31
|
+
:action: :map
|
32
|
+
:with: 1
|
33
|
+
:item: 3
|
34
|
+
- :output1_id: 0
|
35
|
+
:output2_id: 1
|
36
|
+
:output_id: 4
|
37
|
+
:action: :reduce
|
38
|
+
:with: 2
|
39
|
+
- - :output1_id: 2
|
40
|
+
:output2_id: 3
|
41
|
+
:output_id: 5
|
42
|
+
:action: :reduce
|
43
|
+
:with: 0
|
44
|
+
- - :output1_id: 4
|
45
|
+
:output2_id: 5
|
46
|
+
:output_id: 6
|
47
|
+
:action: :reduce
|
48
|
+
:with: 0
|
49
|
+
- - :output_id: 6
|
50
|
+
:action: :finalize
|
51
|
+
:with: 1
|
52
|
+
:final_id: 7
|
@@ -0,0 +1,87 @@
|
|
1
|
+
---
|
2
|
+
- - :secpack: :mapper
|
3
|
+
:action: :migrate
|
4
|
+
:with: 0
|
5
|
+
:to: 1
|
6
|
+
- - :secpack: :mapper
|
7
|
+
:action: :migrate
|
8
|
+
:with: 0
|
9
|
+
:to: 2
|
10
|
+
- :secpack: :mapper
|
11
|
+
:action: :migrate
|
12
|
+
:with: 1
|
13
|
+
:to: 3
|
14
|
+
- - :secpack: :reducer
|
15
|
+
:action: :migrate
|
16
|
+
:with: 0
|
17
|
+
:to: 1
|
18
|
+
- :output_id: 0
|
19
|
+
:action: :map
|
20
|
+
:with: 1
|
21
|
+
:item: 0
|
22
|
+
- :output_id: 1
|
23
|
+
:action: :map
|
24
|
+
:with: 2
|
25
|
+
:item: 1
|
26
|
+
- :output_id: 2
|
27
|
+
:action: :map
|
28
|
+
:with: 3
|
29
|
+
:item: 2
|
30
|
+
- - :secpack: :reducer
|
31
|
+
:action: :migrate
|
32
|
+
:with: 0
|
33
|
+
:to: 2
|
34
|
+
- :secpack: :reducer
|
35
|
+
:action: :migrate
|
36
|
+
:with: 1
|
37
|
+
:to: 3
|
38
|
+
- :output_id: 3
|
39
|
+
:action: :map
|
40
|
+
:with: 2
|
41
|
+
:item: 3
|
42
|
+
- :output_id: 4
|
43
|
+
:action: :map
|
44
|
+
:with: 3
|
45
|
+
:item: 4
|
46
|
+
- - :output_id: 5
|
47
|
+
:action: :map
|
48
|
+
:with: 0
|
49
|
+
:item: 5
|
50
|
+
- :output_id: 6
|
51
|
+
:action: :map
|
52
|
+
:with: 1
|
53
|
+
:item: 6
|
54
|
+
- :output1_id: 0
|
55
|
+
:output2_id: 1
|
56
|
+
:output_id: 7
|
57
|
+
:action: :reduce
|
58
|
+
:with: 2
|
59
|
+
- :output1_id: 2
|
60
|
+
:output2_id: 3
|
61
|
+
:output_id: 8
|
62
|
+
:action: :reduce
|
63
|
+
:with: 3
|
64
|
+
- - :output1_id: 4
|
65
|
+
:output2_id: 5
|
66
|
+
:output_id: 9
|
67
|
+
:action: :reduce
|
68
|
+
:with: 0
|
69
|
+
- :output1_id: 6
|
70
|
+
:output2_id: 7
|
71
|
+
:output_id: 10
|
72
|
+
:action: :reduce
|
73
|
+
:with: 1
|
74
|
+
- - :output1_id: 8
|
75
|
+
:output2_id: 9
|
76
|
+
:output_id: 11
|
77
|
+
:action: :reduce
|
78
|
+
:with: 0
|
79
|
+
- - :output1_id: 10
|
80
|
+
:output2_id: 11
|
81
|
+
:output_id: 12
|
82
|
+
:action: :reduce
|
83
|
+
:with: 0
|
84
|
+
- - :output_id: 12
|
85
|
+
:action: :finalize
|
86
|
+
:with: 0
|
87
|
+
:final_id: 13
|
@@ -0,0 +1,36 @@
|
|
1
|
+
---
|
2
|
+
- - :output_id: 0
|
3
|
+
:action: :map
|
4
|
+
:with: 0
|
5
|
+
:item: 0
|
6
|
+
- - :output_id: 1
|
7
|
+
:action: :map
|
8
|
+
:with: 0
|
9
|
+
:item: 1
|
10
|
+
- - :output_id: 2
|
11
|
+
:action: :map
|
12
|
+
:with: 0
|
13
|
+
:item: 2
|
14
|
+
- - :output_id: 3
|
15
|
+
:action: :map
|
16
|
+
:with: 0
|
17
|
+
:item: 3
|
18
|
+
- - :output1_id: 0
|
19
|
+
:output2_id: 1
|
20
|
+
:output_id: 4
|
21
|
+
:action: :reduce
|
22
|
+
:with: 0
|
23
|
+
- - :output1_id: 2
|
24
|
+
:output2_id: 3
|
25
|
+
:output_id: 5
|
26
|
+
:action: :reduce
|
27
|
+
:with: 0
|
28
|
+
- - :output1_id: 4
|
29
|
+
:output2_id: 5
|
30
|
+
:output_id: 6
|
31
|
+
:action: :reduce
|
32
|
+
:with: 0
|
33
|
+
- - :output_id: 6
|
34
|
+
:action: :finalize
|
35
|
+
:with: 0
|
36
|
+
:final_id: 7
|
@@ -0,0 +1,56 @@
|
|
1
|
+
---
|
2
|
+
- - :secpack: :mapper
|
3
|
+
:action: :migrate
|
4
|
+
:with: 1
|
5
|
+
:to: 0
|
6
|
+
- - :secpack: :mapper
|
7
|
+
:action: :migrate
|
8
|
+
:with: 0
|
9
|
+
:to: 2
|
10
|
+
- :secpack: :reducer
|
11
|
+
:action: :migrate
|
12
|
+
:with: 1
|
13
|
+
:to: 0
|
14
|
+
- - :output_id: 0
|
15
|
+
:action: :map
|
16
|
+
:with: 0
|
17
|
+
:item: 0
|
18
|
+
- :output_id: 1
|
19
|
+
:action: :map
|
20
|
+
:with: 2
|
21
|
+
:item: 1
|
22
|
+
- - :secpack: :reducer
|
23
|
+
:action: :migrate
|
24
|
+
:with: 1
|
25
|
+
:to: 2
|
26
|
+
- - :output_id: 2
|
27
|
+
:action: :map
|
28
|
+
:with: 0
|
29
|
+
:item: 2
|
30
|
+
- - :output_id: 3
|
31
|
+
:action: :map
|
32
|
+
:with: 2
|
33
|
+
:item: 3
|
34
|
+
- - :output1_id: 0
|
35
|
+
:output2_id: 1
|
36
|
+
:output_id: 4
|
37
|
+
:action: :reduce
|
38
|
+
:with: 1
|
39
|
+
- []
|
40
|
+
|
41
|
+
- - :output1_id: 2
|
42
|
+
:output2_id: 3
|
43
|
+
:output_id: 5
|
44
|
+
:action: :reduce
|
45
|
+
:with: 0
|
46
|
+
- []
|
47
|
+
|
48
|
+
- - :output1_id: 4
|
49
|
+
:output2_id: 5
|
50
|
+
:output_id: 6
|
51
|
+
:action: :reduce
|
52
|
+
:with: 0
|
53
|
+
- - :output_id: 6
|
54
|
+
:action: :finalize
|
55
|
+
:with: 1
|
56
|
+
:final_id: 7
|
@@ -0,0 +1,93 @@
|
|
1
|
+
---
|
2
|
+
- - :secpack: :mapper
|
3
|
+
:action: :migrate
|
4
|
+
:with: 0
|
5
|
+
:to: 1
|
6
|
+
- - :secpack: :mapper
|
7
|
+
:action: :migrate
|
8
|
+
:with: 0
|
9
|
+
:to: 2
|
10
|
+
- :secpack: :mapper
|
11
|
+
:action: :migrate
|
12
|
+
:with: 1
|
13
|
+
:to: 3
|
14
|
+
- - :secpack: :reducer
|
15
|
+
:action: :migrate
|
16
|
+
:with: 0
|
17
|
+
:to: 1
|
18
|
+
- :output_id: 0
|
19
|
+
:action: :map
|
20
|
+
:with: 2
|
21
|
+
:item: 0
|
22
|
+
- - :output_id: 1
|
23
|
+
:action: :map
|
24
|
+
:with: 1
|
25
|
+
:item: 1
|
26
|
+
- :output_id: 2
|
27
|
+
:action: :map
|
28
|
+
:with: 3
|
29
|
+
:item: 2
|
30
|
+
- - :secpack: :reducer
|
31
|
+
:action: :migrate
|
32
|
+
:with: 0
|
33
|
+
:to: 2
|
34
|
+
- - :output_id: 3
|
35
|
+
:action: :map
|
36
|
+
:with: 2
|
37
|
+
:item: 3
|
38
|
+
- - :secpack: :reducer
|
39
|
+
:action: :migrate
|
40
|
+
:with: 1
|
41
|
+
:to: 3
|
42
|
+
- - :output_id: 4
|
43
|
+
:action: :map
|
44
|
+
:with: 3
|
45
|
+
:item: 4
|
46
|
+
- - :output_id: 5
|
47
|
+
:action: :map
|
48
|
+
:with: 0
|
49
|
+
:item: 5
|
50
|
+
- - :output_id: 6
|
51
|
+
:action: :map
|
52
|
+
:with: 2
|
53
|
+
:item: 6
|
54
|
+
- - :output1_id: 0
|
55
|
+
:output2_id: 1
|
56
|
+
:output_id: 7
|
57
|
+
:action: :reduce
|
58
|
+
:with: 1
|
59
|
+
- - :output1_id: 2
|
60
|
+
:output2_id: 3
|
61
|
+
:output_id: 8
|
62
|
+
:action: :reduce
|
63
|
+
:with: 3
|
64
|
+
- - :output1_id: 4
|
65
|
+
:output2_id: 5
|
66
|
+
:output_id: 9
|
67
|
+
:action: :reduce
|
68
|
+
:with: 0
|
69
|
+
- []
|
70
|
+
|
71
|
+
- - :output1_id: 6
|
72
|
+
:output2_id: 7
|
73
|
+
:output_id: 10
|
74
|
+
:action: :reduce
|
75
|
+
:with: 1
|
76
|
+
- []
|
77
|
+
|
78
|
+
- - :output1_id: 8
|
79
|
+
:output2_id: 9
|
80
|
+
:output_id: 11
|
81
|
+
:action: :reduce
|
82
|
+
:with: 0
|
83
|
+
- []
|
84
|
+
|
85
|
+
- - :output1_id: 10
|
86
|
+
:output2_id: 11
|
87
|
+
:output_id: 12
|
88
|
+
:action: :reduce
|
89
|
+
:with: 0
|
90
|
+
- - :output_id: 12
|
91
|
+
:action: :finalize
|
92
|
+
:with: 0
|
93
|
+
:final_id: 13
|