fluent-plugin-droonga 0.7.0 → 0.8.0

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.
Files changed (163) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -4
  3. data/benchmark/watch/benchmark-notify.rb +2 -2
  4. data/benchmark/watch/benchmark-scan.rb +3 -0
  5. data/benchmark/watch/fluentd.conf +0 -1
  6. data/fluent-plugin-droonga.gemspec +2 -3
  7. data/lib/droonga/catalog.rb +10 -124
  8. data/lib/droonga/catalog/base.rb +140 -0
  9. data/lib/droonga/catalog/version1.rb +23 -0
  10. data/lib/droonga/catalog_loader.rb +33 -0
  11. data/lib/droonga/collector.rb +2 -71
  12. data/lib/droonga/collector_plugin.rb +2 -34
  13. data/lib/droonga/dispatcher.rb +141 -196
  14. data/lib/droonga/distribution_planner.rb +76 -0
  15. data/lib/droonga/distributor.rb +5 -7
  16. data/lib/droonga/distributor_plugin.rb +23 -15
  17. data/lib/droonga/engine.rb +2 -2
  18. data/lib/droonga/event_loop.rb +46 -0
  19. data/lib/droonga/farm.rb +9 -5
  20. data/lib/droonga/fluent_message_sender.rb +84 -0
  21. data/lib/droonga/forwarder.rb +43 -53
  22. data/lib/droonga/handler.rb +20 -68
  23. data/lib/droonga/handler_message.rb +61 -0
  24. data/lib/droonga/handler_messenger.rb +92 -0
  25. data/lib/droonga/handler_plugin.rb +10 -12
  26. data/lib/droonga/input_adapter.rb +52 -0
  27. data/lib/droonga/{adapter.rb → input_adapter_plugin.rb} +7 -13
  28. data/lib/droonga/input_message.rb +11 -11
  29. data/lib/droonga/logger.rb +4 -3
  30. data/lib/droonga/message_pack_packer.rb +62 -0
  31. data/lib/droonga/message_processing_error.rb +54 -0
  32. data/lib/droonga/message_pusher.rb +60 -0
  33. data/lib/droonga/message_receiver.rb +61 -0
  34. data/lib/droonga/output_adapter.rb +53 -0
  35. data/lib/droonga/{adapter_plugin.rb → output_adapter_plugin.rb} +3 -21
  36. data/lib/droonga/output_message.rb +37 -0
  37. data/lib/droonga/partition.rb +27 -5
  38. data/lib/droonga/pluggable.rb +9 -4
  39. data/lib/droonga/plugin.rb +12 -3
  40. data/lib/droonga/plugin/collector/basic.rb +91 -18
  41. data/lib/droonga/plugin/distributor/crud.rb +9 -9
  42. data/lib/droonga/plugin/distributor/distributed_search_planner.rb +401 -0
  43. data/lib/droonga/plugin/distributor/groonga.rb +5 -5
  44. data/lib/droonga/plugin/distributor/search.rb +4 -246
  45. data/lib/droonga/plugin/distributor/watch.rb +11 -6
  46. data/lib/droonga/plugin/handler/add.rb +69 -7
  47. data/lib/droonga/plugin/handler/groonga.rb +6 -6
  48. data/lib/droonga/plugin/handler/search.rb +5 -3
  49. data/lib/droonga/plugin/handler/watch.rb +19 -13
  50. data/lib/droonga/plugin/{adapter → input_adapter}/groonga.rb +5 -11
  51. data/lib/droonga/plugin/{adapter → input_adapter}/groonga/select.rb +2 -36
  52. data/lib/droonga/plugin/output_adapter/groonga.rb +30 -0
  53. data/lib/droonga/plugin/output_adapter/groonga/select.rb +54 -0
  54. data/lib/droonga/plugin_loader.rb +2 -2
  55. data/lib/droonga/processor.rb +21 -23
  56. data/lib/droonga/replier.rb +40 -0
  57. data/lib/droonga/searcher.rb +298 -174
  58. data/lib/droonga/server.rb +0 -67
  59. data/lib/droonga/session.rb +85 -0
  60. data/lib/droonga/test.rb +21 -0
  61. data/lib/droonga/test/stub_distributor.rb +31 -0
  62. data/lib/droonga/test/stub_handler.rb +37 -0
  63. data/lib/droonga/test/stub_handler_message.rb +35 -0
  64. data/lib/droonga/test/stub_handler_messenger.rb +34 -0
  65. data/lib/droonga/time_formatter.rb +37 -0
  66. data/lib/droonga/watcher.rb +1 -0
  67. data/lib/droonga/worker.rb +16 -19
  68. data/lib/fluent/plugin/out_droonga.rb +9 -9
  69. data/lib/groonga_command_converter.rb +5 -5
  70. data/sample/cluster/catalog.json +1 -1
  71. data/test/command/config/default/catalog.json +19 -1
  72. data/test/command/fixture/event.jsons +41 -0
  73. data/test/command/fixture/user-table.jsons +9 -0
  74. data/test/command/run-test.rb +2 -2
  75. data/test/command/suite/add/error/invalid-integer.expected +20 -0
  76. data/test/command/suite/add/error/invalid-integer.test +12 -0
  77. data/test/command/suite/add/error/invalid-time.expected +20 -0
  78. data/test/command/suite/add/error/invalid-time.test +12 -0
  79. data/test/command/suite/add/error/missing-key.expected +13 -0
  80. data/test/command/suite/add/error/missing-key.test +16 -0
  81. data/test/command/suite/add/error/missing-table.expected +13 -0
  82. data/test/command/suite/add/error/missing-table.test +16 -0
  83. data/test/command/suite/add/error/unknown-column.expected +20 -0
  84. data/test/command/suite/add/error/unknown-column.test +12 -0
  85. data/test/command/suite/add/error/unknown-table.expected +13 -0
  86. data/test/command/suite/add/error/unknown-table.test +17 -0
  87. data/test/command/suite/add/minimum.expected +1 -3
  88. data/test/command/suite/add/with-values.expected +1 -3
  89. data/test/command/suite/add/without-key.expected +1 -3
  90. data/test/command/suite/message/error/missing-dataset.expected +13 -0
  91. data/test/command/suite/message/error/missing-dataset.test +5 -0
  92. data/test/command/suite/message/error/unknown-command.expected +13 -0
  93. data/test/command/suite/message/error/unknown-command.test +6 -0
  94. data/test/command/suite/message/error/unknown-dataset.expected +13 -0
  95. data/test/command/suite/message/error/unknown-dataset.test +6 -0
  96. data/test/command/suite/search/{array-attribute-label.expected → attributes/array.expected} +0 -0
  97. data/test/command/suite/search/{array-attribute-label.test → attributes/array.test} +0 -0
  98. data/test/command/suite/search/{hash-attribute-label.expected → attributes/hash.expected} +0 -0
  99. data/test/command/suite/search/{hash-attribute-label.test → attributes/hash.test} +0 -0
  100. data/test/command/suite/search/{condition-nested.expected → condition/nested.expected} +0 -0
  101. data/test/command/suite/search/{condition-nested.test → condition/nested.test} +0 -0
  102. data/test/command/suite/search/{condition-query.expected → condition/query.expected} +0 -0
  103. data/test/command/suite/search/{condition-query.test → condition/query.test} +0 -0
  104. data/test/command/suite/search/{condition-script.expected → condition/script.expected} +0 -0
  105. data/test/command/suite/search/{condition-script.test → condition/script.test} +0 -0
  106. data/test/command/suite/search/error/cyclic-source.expected +18 -0
  107. data/test/command/suite/search/error/cyclic-source.test +12 -0
  108. data/test/command/suite/search/error/deeply-cyclic-source.expected +21 -0
  109. data/test/command/suite/search/error/deeply-cyclic-source.test +15 -0
  110. data/test/command/suite/search/error/missing-source-parameter.expected +17 -0
  111. data/test/command/suite/search/error/missing-source-parameter.test +11 -0
  112. data/test/command/suite/search/error/unknown-source.expected +18 -0
  113. data/test/command/suite/search/error/unknown-source.test +12 -0
  114. data/test/command/suite/search/{minimum.expected → group/count.expected} +2 -1
  115. data/test/command/suite/search/{minimum.test → group/count.test} +5 -3
  116. data/test/command/suite/search/group/limit.expected +19 -0
  117. data/test/command/suite/search/group/limit.test +20 -0
  118. data/test/command/suite/search/group/string.expected +36 -0
  119. data/test/command/suite/search/group/string.test +44 -0
  120. data/test/command/suite/search/{chained-queries.expected → multiple/chained.expected} +0 -0
  121. data/test/command/suite/search/{chained-queries.test → multiple/chained.test} +0 -0
  122. data/test/command/suite/search/{multiple-queries.expected → multiple/parallel.expected} +0 -0
  123. data/test/command/suite/search/{multiple-queries.test → multiple/parallel.test} +0 -0
  124. data/test/command/suite/search/{output-range.expected → range/only-output.expected} +0 -0
  125. data/test/command/suite/search/{output-range.test → range/only-output.test} +0 -0
  126. data/test/command/suite/search/{sort-range.expected → range/only-sort.expected} +0 -0
  127. data/test/command/suite/search/{sort-range.test → range/only-sort.test} +0 -0
  128. data/test/command/suite/search/{sort-and-output-range.expected → range/sort-and-output.expected} +0 -0
  129. data/test/command/suite/search/{sort-and-output-range.test → range/sort-and-output.test} +0 -0
  130. data/test/command/suite/search/range/too-large-output-offset.expected +16 -0
  131. data/test/command/suite/search/range/too-large-output-offset.test +25 -0
  132. data/test/command/suite/search/range/too-large-sort-offset.expected +16 -0
  133. data/test/command/suite/search/range/too-large-sort-offset.test +28 -0
  134. data/test/command/suite/search/response/records/value/time.expected +24 -0
  135. data/test/command/suite/search/response/records/value/time.test +24 -0
  136. data/test/command/suite/search/sort/default-offset-limit.expected +43 -0
  137. data/test/command/suite/search/sort/default-offset-limit.test +26 -0
  138. data/test/command/suite/search/{sort-with-invisible-column.expected → sort/invisible-column.expected} +0 -0
  139. data/test/command/suite/search/{sort-with-invisible-column.test → sort/invisible-column.test} +0 -0
  140. data/test/command/suite/watch/subscribe.expected +12 -0
  141. data/test/command/suite/watch/subscribe.test +9 -0
  142. data/test/command/suite/watch/unsubscribe.expected +12 -0
  143. data/test/command/suite/watch/unsubscribe.test +9 -0
  144. data/test/unit/{test_catalog.rb → catalog/test_version1.rb} +12 -4
  145. data/test/unit/fixtures/{catalog.json → catalog/version1.json} +0 -0
  146. data/test/unit/helper.rb +2 -0
  147. data/test/unit/plugin/collector/test_basic.rb +289 -33
  148. data/test/unit/plugin/distributor/test_search.rb +176 -861
  149. data/test/unit/plugin/distributor/test_search_planner.rb +1102 -0
  150. data/test/unit/plugin/handler/groonga/test_column_create.rb +17 -13
  151. data/test/unit/plugin/handler/groonga/test_table_create.rb +10 -10
  152. data/test/unit/plugin/handler/test_add.rb +74 -11
  153. data/test/unit/plugin/handler/test_groonga.rb +15 -1
  154. data/test/unit/plugin/handler/test_search.rb +33 -17
  155. data/test/unit/plugin/handler/test_watch.rb +43 -27
  156. data/test/unit/run-test.rb +2 -0
  157. data/test/unit/test_message_pack_packer.rb +51 -0
  158. data/test/unit/test_time_formatter.rb +29 -0
  159. metadata +208 -110
  160. data/lib/droonga/job_queue.rb +0 -87
  161. data/lib/droonga/job_queue_schema.rb +0 -65
  162. data/test/unit/test_adapter.rb +0 -51
  163. data/test/unit/test_job_queue_schema.rb +0 -45
@@ -16,899 +16,214 @@
16
16
  require "droonga/plugin/distributor/search"
17
17
 
18
18
  class SearchDistributorTest < Test::Unit::TestCase
19
- include PluginHelper
20
-
21
19
  def setup
22
20
  setup_database
23
- setup_plugin(Droonga::SearchDistributor)
21
+ @distributor = Droonga::Test::StubDistributor.new
22
+ @plugin = Droonga::SearchDistributor.new(@distributor)
24
23
  end
25
24
 
26
25
  def teardown
27
- teardown_plugin
28
26
  teardown_database
29
27
  end
30
28
 
31
- class MultipleQueriesTest < SearchDistributorTest
32
- def test_distribute
33
- envelope = {
34
- "type" => "search",
35
- "dataset" => "Droonga",
36
- "body" => {
37
- "queries" => {
38
- "query1" => {
39
- "source" => "User",
40
- "output" => {
41
- "format" => "complex",
42
- "elements" => ["count", "records"],
43
- "attributes" => [],
44
- "offset" => 0,
45
- "limit" => 10,
46
- },
47
- },
48
- "query2" => {
49
- "source" => "User",
50
- "output" => {
51
- "format" => "complex",
52
- "elements" => ["count", "records"],
53
- "attributes" => [],
54
- "offset" => 0,
55
- "limit" => 20,
56
- },
57
- },
58
- "query3" => {
59
- "source" => "User",
60
- "output" => {
61
- "format" => "complex",
62
- "elements" => ["count", "records"],
63
- "attributes" => [],
64
- "offset" => 0,
65
- "limit" => 30,
66
- },
67
- },
68
- },
69
- },
70
- }
71
-
72
- @plugin.process("search", envelope)
73
-
74
- message = []
75
-
76
- message << {
77
- "type" => "reduce",
78
- "body" => {
29
+ def test_distribute
30
+ envelope = {
31
+ "type" => "search",
32
+ "dataset" => "Droonga",
33
+ "body" => {
34
+ "queries" => {
79
35
  "query1" => {
80
- "query1_reduced" => {
81
- "count" => {
82
- "type" => "sum",
83
- },
84
- "records" => {
85
- "type" => "sort",
86
- "operators" => [],
87
- "limit" => 10,
88
- },
36
+ "source" => "User",
37
+ "output" => {
38
+ "format" => "complex",
39
+ "elements" => ["count", "records"],
40
+ "attributes" => [],
41
+ "offset" => 0,
42
+ "limit" => 10,
89
43
  },
90
44
  },
91
- },
92
- "inputs" => ["query1"],
93
- "outputs" => ["query1_reduced"],
94
- }
95
- message << {
96
- "type" => "reduce",
97
- "body" => {
98
45
  "query2" => {
99
- "query2_reduced" => {
100
- "count" => {
101
- "type" => "sum",
102
- },
103
- "records" => {
104
- "type" => "sort",
105
- "operators" => [],
106
- "limit" => 20,
107
- },
46
+ "source" => "User",
47
+ "output" => {
48
+ "format" => "complex",
49
+ "elements" => ["count", "records"],
50
+ "attributes" => [],
51
+ "offset" => 0,
52
+ "limit" => 20,
108
53
  },
109
54
  },
110
- },
111
- "inputs" => ["query2"],
112
- "outputs" => ["query2_reduced"],
113
- }
114
- message << {
115
- "type" => "reduce",
116
- "body" => {
117
55
  "query3" => {
118
- "query3_reduced" => {
119
- "count" => {
120
- "type" => "sum",
121
- },
122
- "records" => {
123
- "type" => "sort",
124
- "operators" => [],
125
- "limit" => 30,
126
- },
56
+ "source" => "User",
57
+ "output" => {
58
+ "format" => "complex",
59
+ "elements" => ["count", "records"],
60
+ "attributes" => [],
61
+ "offset" => 0,
62
+ "limit" => 30,
127
63
  },
128
64
  },
129
65
  },
130
- "inputs" => ["query3"],
131
- "outputs" => ["query3_reduced"],
132
- }
66
+ },
67
+ }
133
68
 
134
- gatherer = {
135
- "type" => "gather",
136
- "body" => {
137
- "query1_reduced" => {
138
- "output" => "query1",
139
- "element" => "records",
140
- "offset" => 0,
141
- "limit" => 10,
142
- "format" => "complex",
143
- "attributes" => [],
144
- },
145
- "query2_reduced" => {
146
- "output" => "query2",
147
- "element" => "records",
148
- "offset" => 0,
149
- "limit" => 20,
150
- "format" => "complex",
151
- "attributes" => [],
152
- },
153
- "query3_reduced" => {
154
- "output" => "query3",
155
- "element" => "records",
156
- "offset" => 0,
157
- "limit" => 30,
158
- "format" => "complex",
159
- "attributes" => [],
160
- },
161
- },
162
- "inputs" => [
163
- "query1_reduced",
164
- "query2_reduced",
165
- "query3_reduced",
166
- ],
167
- "post" => true,
168
- }
169
- message << gatherer
170
-
171
- searcher = {
172
- "type" => "broadcast",
173
- "command" => "search",
174
- "dataset" => "Droonga",
175
- "body" => {
176
- "queries" => {
177
- "query1" => {
178
- "source" => "User",
179
- "output" => {
180
- "format" => "simple",
181
- "elements" => ["count", "records"],
182
- "attributes" => [],
183
- "offset" => 0,
184
- "limit" => 10,
185
- },
186
- },
187
- "query2" => {
188
- "source" => "User",
189
- "output" => {
190
- "format" => "simple",
191
- "elements" => ["count", "records"],
192
- "attributes" => [],
193
- "offset" => 0,
194
- "limit" => 20,
195
- },
196
- },
197
- "query3" => {
198
- "source" => "User",
199
- "output" => {
200
- "format" => "simple",
201
- "elements" => ["count", "records"],
202
- "attributes" => [],
203
- "offset" => 0,
204
- "limit" => 30,
205
- },
206
- },
207
- },
208
- },
209
- "outputs" => [
210
- "query1",
211
- "query2",
212
- "query3",
213
- ],
214
- "replica" => "random",
215
- }
216
- message << searcher
217
-
218
- assert_equal(message, @posted.last.last)
219
- end
220
- end
221
-
222
- class SingleQueryTest < SearchDistributorTest
223
- def test_no_output
224
- envelope = {
225
- "type" => "search",
226
- "dataset" => "Droonga",
227
- "body" => {
228
- "queries" => {
229
- "no_output" => {
230
- "source" => "User",
231
- "sortBy" => {
232
- "keys" => ["name"],
233
- "offset" => 0,
234
- "limit" => 1,
235
- },
236
- },
237
- },
238
- },
239
- }
240
-
241
- @plugin.process("search", envelope)
69
+ @plugin.process("search", envelope)
242
70
 
243
- message = []
244
- message << gatherer(envelope, :no_output => true)
245
- message << searcher(envelope, :no_output => true)
246
- assert_equal(message, @posted.last.last)
247
- end
71
+ message = []
248
72
 
249
- def test_no_records_element
250
- envelope = {
251
- "type" => "search",
252
- "dataset" => "Droonga",
253
- "body" => {
254
- "queries" => {
255
- "no_records" => {
256
- "source" => "User",
257
- "sortBy" => {
258
- "keys" => ["name"],
259
- "offset" => 0,
260
- "limit" => 1,
261
- },
262
- "output" => {
263
- "elements" => ["count"],
264
- },
265
- },
266
- },
267
- },
268
- }
269
-
270
- @plugin.process("search", envelope)
271
-
272
- message = []
273
- message << reducer(envelope, {
274
- "count" => {
275
- "type" => "sum",
276
- },
277
- })
278
- message << gatherer(envelope)
279
- message << searcher(envelope, :output_limit => 0)
280
- assert_equal(message, @posted.last.last)
281
- end
282
-
283
- def test_no_output_limit
284
- envelope = {
285
- "type" => "search",
286
- "dataset" => "Droonga",
287
- "body" => {
288
- "queries" => {
289
- "no_limit" => {
290
- "source" => "User",
291
- "output" => {
292
- "format" => "complex",
293
- "elements" => ["count", "records"],
294
- },
295
- },
296
- },
297
- },
298
- }
299
-
300
- @plugin.process("search", envelope)
301
-
302
- message = []
303
- message << reducer(envelope, {
304
- "count" => {
305
- "type" => "sum",
306
- },
307
- })
308
- message << gatherer(envelope)
309
- message << searcher(envelope, :output_offset => 0,
310
- :output_limit => 0)
311
- assert_equal(message, @posted.last.last)
312
- end
313
-
314
- def test_have_records
315
- envelope = {
316
- "type" => "search",
317
- "dataset" => "Droonga",
318
- "body" => {
319
- "queries" => {
320
- "have_records" => {
321
- "source" => "User",
322
- "output" => {
323
- "format" => "complex",
324
- "elements" => ["records"],
325
- "attributes" => ["_key", "name", "age"],
326
- "offset" => 0,
327
- "limit" => 1,
328
- },
329
- },
330
- },
331
- },
332
- }
333
-
334
- @plugin.process("search", envelope)
335
-
336
- message = []
337
- message << reducer(envelope, {
338
- "records" => {
339
- "type" => "sort",
340
- "operators" => [],
341
- "limit" => 1,
342
- },
343
- })
344
- message << gatherer(envelope, :offset => 0,
345
- :limit => 1,
346
- :element => "records",
347
- :format => "complex",
348
- :attributes => ["_key", "name", "age"])
349
- message << searcher(envelope, :output_offset => 0,
350
- :output_limit => 1)
351
- assert_equal(message, @posted.last.last)
352
- end
353
-
354
- def test_have_output_offset
355
- envelope = {
356
- "type" => "search",
357
- "dataset" => "Droonga",
358
- "body" => {
359
- "queries" => {
360
- "have_records" => {
361
- "source" => "User",
362
- "output" => {
363
- "format" => "complex",
364
- "elements" => ["records"],
365
- "attributes" => ["_key", "name", "age"],
366
- "offset" => 1,
367
- "limit" => 1,
368
- },
369
- },
370
- },
371
- },
372
- }
373
-
374
- @plugin.process("search", envelope)
375
-
376
- message = []
377
- message << reducer(envelope, {
378
- "records" => {
379
- "type" => "sort",
380
- "operators" => [],
381
- "limit" => 2,
382
- },
383
- })
384
- message << gatherer(envelope, :offset => 1,
385
- :limit => 1,
386
- :element => "records",
387
- :format => "complex",
388
- :attributes => ["_key", "name", "age"])
389
- message << searcher(envelope, :output_offset => 0,
390
- :output_limit => 2)
391
- assert_equal(message, @posted.last.last)
392
- end
393
-
394
- def test_have_simple_sortBy
395
- envelope = {
396
- "type" => "search",
397
- "dataset" => "Droonga",
398
- "body" => {
399
- "queries" => {
400
- "have_records" => {
401
- "source" => "User",
402
- "sortBy" => ["name"],
403
- "output" => {
404
- "format" => "complex",
405
- "elements" => ["records"],
406
- "attributes" => ["_key", "name", "age"],
407
- "offset" => 0,
408
- "limit" => 1,
409
- },
410
- },
411
- },
412
- },
413
- }
414
-
415
- @plugin.process("search", envelope)
416
-
417
- message = []
418
- message << reducer(envelope, {
419
- "records" => {
420
- "type" => "sort",
421
- "operators" => [
422
- { "column" => 1, "operator" => "<" },
423
- ],
424
- "limit" => 1,
425
- },
426
- })
427
- message << gatherer(envelope, :offset => 0,
428
- :limit => 1,
429
- :element => "records",
430
- :format => "complex",
431
- :attributes => ["_key", "name", "age"])
432
- message << searcher(envelope, :output_offset => 0,
433
- :output_limit => 1)
434
- assert_equal(message, @posted.last.last)
435
- end
436
-
437
- def test_have_sortBy
438
- envelope = {
439
- "type" => "search",
440
- "dataset" => "Droonga",
441
- "body" => {
442
- "queries" => {
443
- "have_records" => {
444
- "source" => "User",
445
- "sortBy" => {
446
- "keys" => ["name"],
447
- },
448
- "output" => {
449
- "format" => "complex",
450
- "elements" => ["records"],
451
- "attributes" => ["_key", "name", "age"],
452
- "offset" => 0,
453
- "limit" => 1,
454
- },
455
- },
456
- },
457
- },
458
- }
459
-
460
- @plugin.process("search", envelope)
461
-
462
- message = []
463
- message << reducer(envelope, {
464
- "records" => {
465
- "type" => "sort",
466
- "operators" => [
467
- { "column" => 1, "operator" => "<" },
468
- ],
469
- "limit" => 1,
470
- },
471
- })
472
- message << gatherer(envelope, :offset => 0,
473
- :limit => 1,
474
- :element => "records",
475
- :format => "complex",
476
- :attributes => ["_key", "name", "age"])
477
- message << searcher(envelope, :sort_offset => 0,
478
- :sort_limit => 1,
479
- :output_offset => 0,
480
- :output_limit => 1)
481
- assert_equal(message, @posted.last.last)
482
- end
483
-
484
- def test_have_sortBy_offset_limit
485
- envelope = {
486
- "type" => "search",
487
- "dataset" => "Droonga",
488
- "body" => {
489
- "queries" => {
490
- "have_records" => {
491
- "source" => "User",
492
- "sortBy" => {
493
- "keys" => ["name"],
494
- "offset" => 1,
495
- "limit" => 2,
496
- },
497
- "output" => {
498
- "format" => "complex",
499
- "elements" => ["records"],
500
- "attributes" => ["_key", "name", "age"],
501
- "offset" => 4,
502
- "limit" => 8,
503
- },
504
- },
505
- },
506
- },
507
- }
508
-
509
- @plugin.process("search", envelope)
510
-
511
- message = []
512
- message << reducer(envelope, {
513
- "records" => {
514
- "type" => "sort",
515
- "operators" => [
516
- { "column" => 1, "operator" => "<" },
517
- ],
518
- "limit" => 1 + 4 + [2, 8].min,
519
- },
520
- })
521
- message << gatherer(envelope, :offset => 5,
522
- :limit => 2,
523
- :element => "records",
524
- :format => "complex",
525
- :attributes => ["_key", "name", "age"])
526
- message << searcher(envelope, :sort_offset => 0,
527
- :sort_limit => 7,
528
- :output_offset => 0,
529
- :output_limit => 7)
530
- assert_equal(message, @posted.last.last)
531
- end
532
-
533
- def test_have_sortBy_with_infinity_output_limit
534
- envelope = {
535
- "type" => "search",
536
- "dataset" => "Droonga",
537
- "body" => {
538
- "queries" => {
539
- "have_records" => {
540
- "source" => "User",
541
- "sortBy" => {
542
- "keys" => ["name"],
543
- "offset" => 1,
544
- "limit" => 2,
545
- },
546
- "output" => {
547
- "format" => "complex",
548
- "elements" => ["records"],
549
- "attributes" => ["_key", "name", "age"],
550
- "offset" => 4,
551
- "limit" => -1,
552
- },
73
+ message << {
74
+ "type" => "reduce",
75
+ "body" => {
76
+ "query1" => {
77
+ "query1_reduced" => {
78
+ "count" => {
79
+ "type" => "sum",
553
80
  },
554
- },
555
- },
556
- }
557
-
558
- @plugin.process("search", envelope)
559
-
560
- message = []
561
- message << reducer(envelope, {
562
- "records" => {
563
- "type" => "sort",
564
- "operators" => [
565
- { "column" => 1, "operator" => "<" },
566
- ],
567
- "limit" => 1 + 4 + 2,
568
- },
569
- })
570
- message << gatherer(envelope, :offset => 5,
571
- :limit => 2,
572
- :element => "records",
573
- :format => "complex",
574
- :attributes => ["_key", "name", "age"])
575
- message << searcher(envelope, :sort_offset => 0,
576
- :sort_limit => 7,
577
- :output_offset => 0,
578
- :output_limit => 7)
579
- assert_equal(message, @posted.last.last)
580
- end
581
-
582
- def test_have_sortBy_with_infinity_sort_limit
583
- envelope = {
584
- "type" => "search",
585
- "dataset" => "Droonga",
586
- "body" => {
587
- "queries" => {
588
- "have_records" => {
589
- "source" => "User",
590
- "sortBy" => {
591
- "keys" => ["name"],
592
- "offset" => 1,
593
- "limit" => -1,
594
- },
595
- "output" => {
596
- "format" => "complex",
597
- "elements" => ["records"],
598
- "attributes" => ["_key", "name", "age"],
599
- "offset" => 4,
600
- "limit" => 8,
601
- },
81
+ "records" => {
82
+ "type" => "sort",
83
+ "operators" => [],
84
+ "limit" => 10,
602
85
  },
603
86
  },
604
87
  },
605
- }
606
-
607
- @plugin.process("search", envelope)
608
-
609
- message = []
610
- message << reducer(envelope, {
611
- "records" => {
612
- "type" => "sort",
613
- "operators" => [
614
- { "column" => 1, "operator" => "<" },
615
- ],
616
- "limit" => 1 + 4 + 8,
617
- },
618
- })
619
- message << gatherer(envelope, :offset => 5,
620
- :limit => 8,
621
- :element => "records",
622
- :format => "complex",
623
- :attributes => ["_key", "name", "age"])
624
- message << searcher(envelope, :sort_offset => 0,
625
- :sort_limit => 8,
626
- :output_offset => 0,
627
- :output_limit => 8)
628
- assert_equal(message, @posted.last.last)
629
- end
630
-
631
- def test_have_sortBy_with_infinity_limit
632
- envelope = {
633
- "type" => "search",
634
- "dataset" => "Droonga",
635
- "body" => {
636
- "queries" => {
637
- "have_records" => {
638
- "source" => "User",
639
- "sortBy" => {
640
- "keys" => ["name"],
641
- "offset" => 1,
642
- "limit" => -1,
643
- },
644
- "output" => {
645
- "format" => "complex",
646
- "elements" => ["records"],
647
- "attributes" => ["_key", "name", "age"],
648
- "offset" => 4,
649
- "limit" => -1,
650
- },
88
+ },
89
+ "inputs" => ["query1"],
90
+ "outputs" => ["query1_reduced"],
91
+ }
92
+ message << {
93
+ "type" => "reduce",
94
+ "body" => {
95
+ "query2" => {
96
+ "query2_reduced" => {
97
+ "count" => {
98
+ "type" => "sum",
651
99
  },
652
- },
653
- },
654
- }
655
-
656
- @plugin.process("search", envelope)
657
-
658
- message = []
659
- message << reducer(envelope, {
660
- "records" => {
661
- "type" => "sort",
662
- "operators" => [
663
- { "column" => 1, "operator" => "<" },
664
- ],
665
- "limit" => -1,
666
- },
667
- })
668
- message << gatherer(envelope, :offset => 5,
669
- :limit => -1,
670
- :element => "records",
671
- :format => "complex",
672
- :attributes => ["_key", "name", "age"])
673
- message << searcher(envelope, :sort_offset => 0,
674
- :sort_limit => -1,
675
- :output_offset => 0,
676
- :output_limit => -1)
677
- assert_equal(message, @posted.last.last)
678
- end
679
-
680
- def test_have_sortBy_with_multiple_sort_keys
681
- envelope = {
682
- "type" => "search",
683
- "dataset" => "Droonga",
684
- "body" => {
685
- "queries" => {
686
- "have_records" => {
687
- "source" => "User",
688
- "sortBy" => {
689
- "keys" => ["-age", "name"],
690
- "limit" => -1,
691
- },
692
- "output" => {
693
- "format" => "complex",
694
- "elements" => ["records"],
695
- "attributes" => ["_key", "name", "age"],
696
- "limit" => -1,
697
- },
100
+ "records" => {
101
+ "type" => "sort",
102
+ "operators" => [],
103
+ "limit" => 20,
698
104
  },
699
105
  },
700
106
  },
701
- }
702
-
703
- @plugin.process("search", envelope)
704
-
705
- message = []
706
- message << reducer(envelope, {
707
- "records" => {
708
- "type" => "sort",
709
- "operators" => [
710
- { "column" => 2, "operator" => ">" },
711
- { "column" => 1, "operator" => "<" },
712
- ],
713
- "limit" => -1,
714
- },
715
- })
716
- message << gatherer(envelope, :offset => 0,
717
- :limit => -1,
718
- :element => "records",
719
- :format => "complex",
720
- :attributes => ["_key", "name", "age"])
721
- message << searcher(envelope, :sort_offset => 0,
722
- :sort_limit => -1,
723
- :output_offset => 0,
724
- :output_limit => -1)
725
- assert_equal(message, @posted.last.last)
726
- end
727
-
728
- def test_have_sortBy_with_missing_sort_attributes
729
- envelope = {
730
- "type" => "search",
731
- "dataset" => "Droonga",
732
- "body" => {
733
- "queries" => {
734
- "have_records" => {
735
- "source" => "User",
736
- "sortBy" => {
737
- "keys" => ["-public_age", "public_name"],
738
- "limit" => -1,
739
- },
740
- "output" => {
741
- "format" => "complex",
742
- "elements" => ["records"],
743
- "attributes" => ["_key", "name", "age"],
744
- "limit" => -1,
745
- },
107
+ },
108
+ "inputs" => ["query2"],
109
+ "outputs" => ["query2_reduced"],
110
+ }
111
+ message << {
112
+ "type" => "reduce",
113
+ "body" => {
114
+ "query3" => {
115
+ "query3_reduced" => {
116
+ "count" => {
117
+ "type" => "sum",
118
+ },
119
+ "records" => {
120
+ "type" => "sort",
121
+ "operators" => [],
122
+ "limit" => 30,
123
+ },
124
+ },
125
+ },
126
+ },
127
+ "inputs" => ["query3"],
128
+ "outputs" => ["query3_reduced"],
129
+ }
130
+
131
+ gatherer = {
132
+ "type" => "gather",
133
+ "body" => {
134
+ "query1_reduced" => {
135
+ "output" => "query1",
136
+ "elements" => {
137
+ "records" => {
138
+ "type" => "sort",
139
+ "offset" => 0,
140
+ "limit" => 10,
141
+ "format" => "complex",
142
+ "attributes" => [],
143
+ },
144
+ },
145
+ },
146
+ "query2_reduced" => {
147
+ "output" => "query2",
148
+ "elements" => {
149
+ "records" => {
150
+ "type" => "sort",
151
+ "offset" => 0,
152
+ "limit" => 20,
153
+ "format" => "complex",
154
+ "attributes" => [],
155
+ },
156
+ },
157
+ },
158
+ "query3_reduced" => {
159
+ "output" => "query3",
160
+ "elements" => {
161
+ "records" => {
162
+ "type" => "sort",
163
+ "offset" => 0,
164
+ "limit" => 30,
165
+ "format" => "complex",
166
+ "attributes" => [],
167
+ },
168
+ },
169
+ },
170
+ },
171
+ "inputs" => [
172
+ "query1_reduced",
173
+ "query2_reduced",
174
+ "query3_reduced",
175
+ ],
176
+ "post" => true,
177
+ }
178
+ message << gatherer
179
+
180
+ searcher = {
181
+ "type" => "broadcast",
182
+ "command" => "search",
183
+ "dataset" => "Droonga",
184
+ "body" => {
185
+ "queries" => {
186
+ "query1" => {
187
+ "source" => "User",
188
+ "output" => {
189
+ "format" => "simple",
190
+ "elements" => ["count", "records"],
191
+ "attributes" => [],
192
+ "offset" => 0,
193
+ "limit" => 10,
746
194
  },
747
195
  },
748
- },
749
- }
750
-
751
- @plugin.process("search", envelope)
752
-
753
- message = []
754
- message << reducer(envelope, {
755
- "records" => {
756
- "type" => "sort",
757
- "operators" => [
758
- { "column" => 3, "operator" => ">" },
759
- { "column" => 4, "operator" => "<" },
760
- ],
761
- "limit" => -1,
762
- },
763
- })
764
- message << gatherer(envelope, :offset => 0,
765
- :limit => -1,
766
- :element => "records",
767
- :format => "complex",
768
- :attributes => ["_key", "name", "age"])
769
- message << searcher(envelope, :sort_offset => 0,
770
- :sort_limit => -1,
771
- :output_offset => 0,
772
- :output_limit => -1,
773
- :extra_attributes => ["public_age", "public_name"])
774
- assert_equal(message, @posted.last.last)
775
- end
776
-
777
- def test_hash_attributes
778
- envelope = {
779
- "type" => "search",
780
- "dataset" => "Droonga",
781
- "body" => {
782
- "queries" => {
783
- "have_records" => {
784
- "source" => "User",
785
- "sortBy" => {
786
- "keys" => ["-public_age", "public_name"],
787
- "limit" => -1,
788
- },
789
- "output" => {
790
- "format" => "complex",
791
- "elements" => ["records"],
792
- "attributes" => {
793
- "id" => "_key",
794
- "name" => { "source" => "name" },
795
- "age" => { "source" => "age" },
796
- },
797
- "limit" => -1,
798
- },
196
+ "query2" => {
197
+ "source" => "User",
198
+ "output" => {
199
+ "format" => "simple",
200
+ "elements" => ["count", "records"],
201
+ "attributes" => [],
202
+ "offset" => 0,
203
+ "limit" => 20,
799
204
  },
800
205
  },
801
- },
802
- }
803
-
804
- @plugin.process("search", envelope)
805
-
806
- message = []
807
- message << reducer(envelope, {
808
- "records" => {
809
- "type" => "sort",
810
- "operators" => [
811
- { "column" => 3, "operator" => ">" },
812
- { "column" => 4, "operator" => "<" },
813
- ],
814
- "limit" => -1,
815
- },
816
- })
817
- message << gatherer(envelope, :offset => 0,
818
- :limit => -1,
819
- :element => "records",
820
- :format => "complex",
821
- :attributes => ["id", "name", "age"])
822
- message << searcher(envelope, :sort_offset => 0,
823
- :sort_limit => -1,
824
- :output_offset => 0,
825
- :output_limit => -1,
826
- :extra_attributes => ["public_age", "public_name"])
827
- assert_equal(message, @posted.last.last)
828
- end
829
-
830
- private
831
- def reducer(search_request_envelope, reducer_body)
832
- queries = search_request_envelope["body"]["queries"]
833
- query_name = queries.keys.first
834
-
835
- reducer = {
836
- "type" => "reduce",
837
- "body" => {
838
- query_name => {
839
- "#{query_name}_reduced" => reducer_body,
840
- },
841
- },
842
- "inputs" => [query_name],
843
- "outputs" => ["#{query_name}_reduced"],
844
- }
845
-
846
- reducer
847
- end
848
-
849
- def gatherer(search_request_envelope, options={})
850
- queries = search_request_envelope["body"]["queries"]
851
- query_name = queries.keys.first
852
-
853
- gatherer = {
854
- "type" => "gather",
855
- "body" => {
856
- },
857
- "inputs" => [
858
- ],
859
- "post" => true,
860
- }
861
-
862
- unless options[:no_output]
863
- output = {
864
- "output" => query_name,
865
- }
866
- if options[:element]
867
- output.merge!({
868
- "element" => options[:element],
869
- "offset" => options[:offset] || 0,
870
- "limit" => options[:limit] || 0,
871
- "format" => options[:format] || "simple",
872
- "attributes" => options[:attributes] || [],
873
- })
874
- end
875
- gatherer["body"]["#{query_name}_reduced"] = output
876
- gatherer["inputs"] << "#{query_name}_reduced"
877
- end
878
-
879
- gatherer
880
- end
881
-
882
- def searcher(search_request_envelope, options={})
883
- searcher = search_request_envelope.dup
884
-
885
- queries = searcher["body"]["queries"]
886
- query_name = queries.keys.first
887
- query = queries.values.first
888
- if options[:extra_attributes]
889
- query["output"]["attributes"] += options[:extra_attributes]
890
- end
891
- if options[:sort_offset]
892
- query["sortBy"]["offset"] = options[:sort_offset]
893
- end
894
- if options[:sort_limit]
895
- query["sortBy"]["limit"] = options[:sort_limit]
896
- end
897
- if options[:output_offset]
898
- query["output"]["offset"] = options[:output_offset]
899
- end
900
- if options[:output_limit]
901
- query["output"]["limit"] = options[:output_limit]
902
- end
903
-
904
- outputs = []
905
- outputs << query_name unless options[:no_output]
906
-
907
- searcher["type"] = "broadcast"
908
- searcher["command"] = "search"
909
- searcher["outputs"] = outputs
910
- searcher["replica"] = "random"
911
- searcher
912
- end
206
+ "query3" => {
207
+ "source" => "User",
208
+ "output" => {
209
+ "format" => "simple",
210
+ "elements" => ["count", "records"],
211
+ "attributes" => [],
212
+ "offset" => 0,
213
+ "limit" => 30,
214
+ },
215
+ },
216
+ },
217
+ },
218
+ "outputs" => [
219
+ "query1",
220
+ "query2",
221
+ "query3",
222
+ ],
223
+ "replica" => "random",
224
+ }
225
+ message << searcher
226
+
227
+ assert_equal([message], @distributor.messages)
913
228
  end
914
229
  end