tem_mr_search 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|