fluent-plugin-droonga 1.0.0 → 1.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.
Files changed (90) hide show
  1. data/.travis.yml +1 -1
  2. data/Gemfile +1 -1
  3. data/fluent-plugin-droonga.gemspec +1 -1
  4. data/lib/droonga/catalog/collection_volume.rb +97 -0
  5. data/lib/droonga/catalog/dataset.rb +28 -1
  6. data/lib/droonga/catalog/errors.rb +28 -9
  7. data/lib/droonga/catalog/schema.rb +23 -2
  8. data/lib/droonga/catalog/single_volume.rb +28 -0
  9. data/lib/droonga/catalog/slice.rb +43 -0
  10. data/lib/droonga/catalog/version1.rb +3 -3
  11. data/lib/droonga/catalog/version2.rb +17 -81
  12. data/lib/droonga/catalog/version2_validator.rb +63 -0
  13. data/lib/droonga/catalog/volume.rb +33 -0
  14. data/lib/droonga/catalog/volume_collection.rb +56 -0
  15. data/lib/droonga/catalog_observer.rb +7 -19
  16. data/lib/droonga/collectors.rb +1 -1
  17. data/lib/droonga/collectors/{add.rb → or.rb} +1 -1
  18. data/lib/droonga/dispatcher.rb +24 -18
  19. data/lib/droonga/distributed_command_planner.rb +7 -11
  20. data/lib/droonga/distributor.rb +29 -17
  21. data/lib/droonga/event_loop.rb +2 -11
  22. data/lib/droonga/fluent_message_sender.rb +51 -5
  23. data/lib/droonga/handler_runner.rb +1 -1
  24. data/lib/droonga/job_protocol.rb +20 -0
  25. data/lib/droonga/job_pusher.rb +178 -0
  26. data/lib/droonga/{message_receiver.rb → job_receiver.rb} +13 -6
  27. data/lib/droonga/message_matcher.rb +18 -15
  28. data/lib/droonga/planner.rb +2 -3
  29. data/lib/droonga/plugins/crud.rb +1 -1
  30. data/lib/droonga/plugins/groonga/column_create.rb +4 -1
  31. data/lib/droonga/plugins/groonga/table_create.rb +1 -1
  32. data/lib/droonga/plugins/groonga/table_remove.rb +1 -1
  33. data/lib/droonga/plugins/search/distributed_search_planner.rb +9 -0
  34. data/lib/droonga/processor.rb +3 -3
  35. data/lib/droonga/reducer.rb +15 -12
  36. data/lib/droonga/searcher.rb +49 -4
  37. data/lib/droonga/server.rb +2 -0
  38. data/lib/droonga/single_step.rb +22 -7
  39. data/lib/droonga/slice.rb +7 -7
  40. data/lib/droonga/step_runner.rb +3 -2
  41. data/lib/droonga/worker.rb +10 -8
  42. data/test/command/suite/add/dimension/column.catalog.json +27 -0
  43. data/test/command/suite/add/dimension/column.expected +57 -0
  44. data/test/command/suite/add/dimension/column.test +51 -0
  45. data/test/command/suite/search/adjusters/multiple.catalog.json +38 -0
  46. data/test/command/suite/search/adjusters/multiple.expected +23 -0
  47. data/test/command/suite/search/adjusters/multiple.test +75 -0
  48. data/test/command/suite/search/adjusters/one.catalog.json +38 -0
  49. data/test/command/suite/search/adjusters/one.expected +23 -0
  50. data/test/command/suite/search/adjusters/one.test +66 -0
  51. data/test/command/suite/search/attributes/array.test +0 -2
  52. data/test/command/suite/search/attributes/hash.test +0 -2
  53. data/test/command/suite/search/complex.test +0 -2
  54. data/test/command/suite/search/condition/nested.test +0 -2
  55. data/test/command/suite/search/condition/query.test +0 -2
  56. data/test/command/suite/search/condition/script.test +0 -2
  57. data/test/command/suite/search/group/string.test +0 -4
  58. data/test/command/suite/search/group/subrecord/with-sort.catalog.json +33 -0
  59. data/test/command/suite/search/group/subrecord/with-sort.expected +34 -0
  60. data/test/command/suite/search/group/subrecord/with-sort.test +81 -0
  61. data/test/command/suite/search/multiple/chained.test +0 -4
  62. data/test/command/suite/search/multiple/parallel.test +0 -4
  63. data/test/command/suite/search/range/only-output.test +0 -2
  64. data/test/command/suite/search/range/only-sort.test +0 -2
  65. data/test/command/suite/search/range/sort-and-output.test +0 -2
  66. data/test/command/suite/search/range/too-large-output-offset.test +0 -2
  67. data/test/command/suite/search/range/too-large-sort-offset.test +0 -2
  68. data/test/command/suite/search/response/elapsed_time.catalog.json +13 -0
  69. data/test/command/suite/search/response/elapsed_time.expected +15 -0
  70. data/test/command/suite/search/response/elapsed_time.test +26 -0
  71. data/test/command/suite/search/response/records/value/time.test +0 -2
  72. data/test/command/suite/search/simple.test +0 -2
  73. data/test/command/suite/search/sort/default-offset-limit.test +0 -2
  74. data/test/command/suite/search/sort/invisible-column.test +0 -2
  75. data/test/unit/catalog/test_collection_volume.rb +103 -0
  76. data/test/unit/catalog/test_dataset.rb +69 -8
  77. data/test/unit/catalog/test_schema.rb +63 -23
  78. data/test/unit/catalog/test_single_volume.rb +31 -0
  79. data/test/unit/catalog/test_slice.rb +92 -0
  80. data/test/unit/catalog/test_version1.rb +1 -1
  81. data/test/unit/catalog/test_version2.rb +1 -32
  82. data/test/unit/catalog/test_version2_validator.rb +66 -0
  83. data/test/unit/catalog/test_volume_collection.rb +50 -0
  84. data/test/unit/plugins/groonga/test_column_create.rb +4 -1
  85. data/test/unit/plugins/groonga/test_table_create.rb +1 -1
  86. data/test/unit/test_message_matcher.rb +15 -15
  87. data/test/unit/test_watch_schema.rb +1 -1
  88. metadata +107 -94
  89. checksums.yaml +0 -7
  90. data/lib/droonga/message_pusher.rb +0 -64
@@ -69,6 +69,9 @@ module Droonga
69
69
  options[:type] = :scalar
70
70
  elsif @command.column_vector?
71
71
  options[:type] = :vector
72
+ if @command.with_weight?
73
+ options[:with_weight] = true
74
+ end
72
75
  end
73
76
  options
74
77
  end
@@ -120,7 +123,7 @@ module Droonga
120
123
  step.name = "column_create"
121
124
  step.write = true
122
125
  step.handler = Handler
123
- step.collector = Collectors::Add
126
+ step.collector = Collectors::Or
124
127
  end
125
128
  end
126
129
  end
@@ -103,7 +103,7 @@ module Droonga
103
103
  step.name = "table_create"
104
104
  step.write = true
105
105
  step.handler = Handler
106
- step.collector = Collectors::Add
106
+ step.collector = Collectors::Or
107
107
  end
108
108
  end
109
109
  end
@@ -54,7 +54,7 @@ module Droonga
54
54
  step.name = "table_remove"
55
55
  step.write = true
56
56
  step.handler = Handler
57
- step.collector = Collectors::Add
57
+ step.collector = Collectors::Or
58
58
  end
59
59
  end
60
60
  end
@@ -122,6 +122,7 @@ module Droonga
122
122
 
123
123
  calculate_offset_and_limit!
124
124
  build_count_mapper_and_reducer!
125
+ build_elapsed_time_mapper_and_reducer!
125
126
  build_records_mapper_and_reducer!
126
127
  end
127
128
 
@@ -256,6 +257,14 @@ module Droonga
256
257
  end
257
258
  end
258
259
 
260
+ def build_elapsed_time_mapper_and_reducer!
261
+ return unless @output["elements"].include?("elapsedTime")
262
+
263
+ @reducers["elapsedTime"] = {
264
+ "type" => "sum",
265
+ }
266
+ end
267
+
259
268
  def build_records_mapper_and_reducer!
260
269
  # Skip reducing phase for a result with no record output.
261
270
  return if !@output["elements"].include?("records") || @records_limit.zero?
@@ -20,9 +20,9 @@ module Droonga
20
20
  class Processor
21
21
  include Loggable
22
22
 
23
- def initialize(loop, message_pusher, options={})
23
+ def initialize(loop, job_pusher, options={})
24
24
  @loop = loop
25
- @message_pusher = message_pusher
25
+ @job_pusher = job_pusher
26
26
  @options = options
27
27
  @n_workers = @options[:n_workers] || 0
28
28
  end
@@ -47,7 +47,7 @@ module Droonga
47
47
  if @n_workers.zero? or synchronous
48
48
  @handler_runner.process(message)
49
49
  else
50
- @message_pusher.push(message)
50
+ @job_pusher.push(message)
51
51
  end
52
52
  else
53
53
  logger.trace("process: ignore #{type}")
@@ -134,25 +134,28 @@ module Droonga
134
134
  base_items, unified_items = unified_items, base_items
135
135
  end
136
136
 
137
- rest_unified_items = unified_items.dup
137
+ unified_key_map = {}
138
+ unified_items.each do |unified_item|
139
+ unified_key_map[unified_item[key_column_index]] = unified_item
140
+ end
138
141
 
142
+ unified = false
139
143
  base_items.reject! do |base_item|
140
144
  key = base_item[key_column_index]
141
- rest_unified_items.any? do |unified_item|
142
- if unified_item[key_column_index] == key
143
- base_item.each_with_index do |value, column|
144
- next if column == key_column_index
145
- unified_item[column] += value
146
- end
147
- rest_unified_items -= [unified_item]
148
- true
149
- else
150
- false
145
+ unified_item = unified_key_map[key]
146
+ if unified_item
147
+ base_item.each_with_index do |value, column_index|
148
+ next if column_index == key_column_index
149
+ unified_item[column_index] += value
151
150
  end
151
+ unified = true
152
+ true
153
+ else
154
+ false
152
155
  end
153
156
  end
154
157
 
155
- unless rest_unified_items.size == unified_items.size
158
+ if unified
156
159
  unified_items.sort! do |a, b|
157
160
  if compare(a, b, options[:operators])
158
161
  -1
@@ -61,14 +61,26 @@ module Droonga
61
61
  def search(queries)
62
62
  outputs = nil
63
63
  logger.trace("search: start", :queries => queries)
64
- @context.push_memory_pool do
65
- outputs = process_queries(queries)
64
+ # TODO: THIS IS JUST A WORKAROUND! We should remove it ASAP!
65
+ disable_gc do
66
+ @context.push_memory_pool do
67
+ outputs = process_queries(queries)
68
+ end
66
69
  end
67
70
  logger.trace("search: done")
68
71
  return outputs
69
72
  end
70
73
 
71
74
  private
75
+ def disable_gc
76
+ GC.disable
77
+ begin
78
+ yield
79
+ ensure
80
+ GC.enable
81
+ end
82
+ end
83
+
72
84
  def process_queries(queries)
73
85
  logger.trace("process_queries: start")
74
86
  if queries.nil? or queries.empty?
@@ -302,7 +314,12 @@ module Droonga
302
314
  @records = @request.source
303
315
 
304
316
  condition = @request.query["condition"]
305
- apply_condition!(condition) if condition
317
+ if condition
318
+ apply_condition!(condition)
319
+
320
+ adjusters = @request.query["adjusters"]
321
+ apply_adjusters!(adjusters) if adjusters
322
+ end
306
323
 
307
324
  group_by = @request.query["groupBy"]
308
325
  apply_group_by!(group_by) if group_by
@@ -328,6 +345,29 @@ module Droonga
328
345
  @result.condition = expression
329
346
  end
330
347
 
348
+ def apply_adjusters!(adjusters)
349
+ logger.trace("search_query: adjusters: start")
350
+ adjusters.each do |adjuster|
351
+ column_name = adjuster["column"]
352
+ value = adjuster["value"]
353
+ factor = adjuster["factor"] || 1
354
+ logger.trace("search_query: adjusters: adjuster: start",
355
+ :column_name => column_name,
356
+ :value => value,
357
+ :factor => factor)
358
+ column = @request.source.column(column_name)
359
+ index, = column.indexes(:match)
360
+ # TODO: add index.nil? check
361
+ # TODO: add value.nil? check
362
+ index.search(value,
363
+ :result => @records,
364
+ :operator => :adjust,
365
+ :weight => factor)
366
+ logger.trace("search_query: adjusters: adjuster: done")
367
+ end
368
+ logger.trace("search_query: adjusters: done")
369
+ end
370
+
331
371
  def apply_group_by!(group_by)
332
372
  logger.trace("search_query: group: start",
333
373
  :by => group_by)
@@ -449,7 +489,12 @@ module Droonga
449
489
  module RecordsFormattable
450
490
  def record_value(record, attribute)
451
491
  if attribute[:source] == "_subrecs"
452
- record.sub_records.collect do |sub_record|
492
+ if record.table.is_a?(Groonga::Array)
493
+ target_record = record.value
494
+ else
495
+ target_record = record
496
+ end
497
+ target_record.sub_records.collect do |sub_record|
453
498
  sub_attributes = attribute[:attributes]
454
499
  format_record(sub_attributes, sub_record)
455
500
  end
@@ -21,6 +21,8 @@ module Droonga
21
21
  module Server
22
22
  def before_run
23
23
  Droonga.logger.trace("#{log_tag}: before_run: start")
24
+ config[:job_pusher].close
25
+ config.delete(:job_pusher)
24
26
  Droonga.logger.trace("#{log_tag}: before_run: done")
25
27
  end
26
28
 
@@ -18,7 +18,8 @@ require "droonga/collectors"
18
18
 
19
19
  module Droonga
20
20
  class SingleStep
21
- def initialize(definition)
21
+ def initialize(dataset, definition)
22
+ @dataset = dataset
22
23
  @definition = definition
23
24
  end
24
25
 
@@ -40,14 +41,28 @@ module Droonga
40
41
  reduce_key => collector_class.operator,
41
42
  }
42
43
  end
43
- inputs = @definition.inputs
44
- if inputs.empty?
45
- planner.send(:broadcast, message, options)
44
+
45
+ body = message["body"]
46
+ fact_input = find_fact_input(@definition.inputs, @dataset.fact, body)
47
+ if fact_input
48
+ record = body[fact_input[:filter]]
49
+ planner.send(:scatter, message, record, options)
46
50
  else
47
- input = inputs.values.first
48
- options[:key] = message["body"][input[:filter]]["key"]
49
- planner.send(:scatter, message, options)
51
+ planner.send(:broadcast, message, options)
52
+ end
53
+ end
54
+
55
+ def find_fact_input(inputs, fact, body)
56
+ inputs.each do |key, input|
57
+ if input[:type] == :table
58
+ # for backward compatibility. We can remove the following code
59
+ # when all our catalog.json specify "fact" parameter.
60
+ return input if fact.nil?
61
+
62
+ return input if body[key] == fact
63
+ end
50
64
  end
65
+ nil
51
66
  end
52
67
  end
53
68
  end
@@ -19,7 +19,7 @@ require "droonga/loggable"
19
19
  require "droonga/server"
20
20
  require "droonga/worker"
21
21
  require "droonga/event_loop"
22
- require "droonga/message_pusher"
22
+ require "droonga/job_pusher"
23
23
  require "droonga/processor"
24
24
 
25
25
  module Droonga
@@ -30,23 +30,22 @@ module Droonga
30
30
  @options = options
31
31
  @n_workers = @options[:n_workers] || 0
32
32
  @loop = loop
33
- @message_pusher = MessagePusher.new(@loop)
34
- @processor = Processor.new(@loop, @message_pusher, @options)
33
+ @job_pusher = JobPusher.new(@loop, @options[:database])
34
+ @processor = Processor.new(@loop, @job_pusher, @options)
35
35
  @supervisor = nil
36
36
  end
37
37
 
38
38
  def start
39
39
  ensure_database
40
40
  @processor.start
41
- base_path = @options[:database]
42
- @message_pusher.start(base_path)
41
+ @job_pusher.start
43
42
  start_supervisor if @n_workers > 0
44
43
  end
45
44
 
46
45
  def shutdown
47
46
  logger.trace("shutdown: start")
48
47
  shutdown_supervisor if @supervisor
49
- @message_pusher.shutdown
48
+ @job_pusher.shutdown
50
49
  @processor.shutdown
51
50
  logger.trace("shutdown: done")
52
51
  end
@@ -84,7 +83,8 @@ module Droonga
84
83
  :log_level => logger.level,
85
84
  :server_process_name => "Server[#{@options[:database]}] #$0",
86
85
  :worker_process_name => "Worker[#{@options[:database]}] #$0",
87
- :message_receiver => @message_pusher.raw_receiver,
86
+ :job_receive_socket_path => @job_pusher.socket_path,
87
+ :job_pusher => @job_pusher,
88
88
  }
89
89
  @options.merge(force_options)
90
90
  end
@@ -21,7 +21,8 @@ module Droonga
21
21
  class StepRunner
22
22
  include Loggable
23
23
 
24
- def initialize(plugins)
24
+ def initialize(dataset, plugins)
25
+ @dataset = dataset
25
26
  @definitions = {}
26
27
  plugins.each do |name|
27
28
  plugin = Plugin.registry[name]
@@ -43,7 +44,7 @@ module Droonga
43
44
  if definition.nil?
44
45
  raise UnsupportedMessageError.new(:planner, message)
45
46
  end
46
- step = SingleStep.new(definition)
47
+ step = SingleStep.new(@dataset, definition)
47
48
  plan = step.plan(message)
48
49
  logger.trace("plan: done",
49
50
  :dataset => message["dataset"],
@@ -15,16 +15,17 @@
15
15
 
16
16
  require "droonga/event_loop"
17
17
  require "droonga/handler_runner"
18
- require "droonga/message_receiver"
18
+ require "droonga/job_receiver"
19
19
 
20
20
  module Droonga
21
21
  module Worker
22
22
  def initialize
23
- @loop = EventLoop.new
23
+ @raw_loop = Coolio::Loop.new
24
+ @loop = EventLoop.new(@raw_loop)
24
25
  @handler_runner = HandlerRunner.new(@loop,
25
26
  config.merge(:dispatcher => nil))
26
- receiver_socket = config[:message_receiver]
27
- @message_receiver = MessageReceiver.new(@loop, receiver_socket) do |message|
27
+ receive_socket_path = config[:job_receive_socket_path]
28
+ @job_receiver = JobReceiver.new(@loop, receive_socket_path) do |message|
28
29
  process(message)
29
30
  end
30
31
  end
@@ -32,16 +33,17 @@ module Droonga
32
33
  def run
33
34
  Droonga.logger.trace("#{log_tag}: run: start")
34
35
  @handler_runner.start
35
- @message_receiver.start
36
- @loop.run
36
+ @job_receiver.start
37
+ @raw_loop.run
37
38
  @handler_runner.shutdown
38
39
  Droonga.logger.trace("#{log_tag}: run: done")
39
40
  end
40
41
 
41
42
  def stop
42
43
  Droonga.logger.trace("#{log_tag}: stop: start")
43
- @message_receiver.shutdown
44
- @loop.stop
44
+ @job_receiver.shutdown
45
+ @raw_loop.stop
46
+ @loop.break_current_loop
45
47
  Droonga.logger.trace("#{log_tag}: stop: done")
46
48
  end
47
49
 
@@ -0,0 +1,27 @@
1
+ {
2
+ "datasets": {
3
+ "Droonga": {
4
+ "schema": {
5
+ "Products": {
6
+ "type": "Hash",
7
+ "keyType": "ShortText",
8
+ "columns": {
9
+ "category": {
10
+ "type": "Scalar",
11
+ "valueType": "ShortText"
12
+ }
13
+ }
14
+ }
15
+ },
16
+ "replicas": [
17
+ {
18
+ "dimension": "category"
19
+ },
20
+ {
21
+ "dimension": "category"
22
+ }
23
+ ]
24
+ }
25
+ }
26
+ }
27
+
@@ -0,0 +1,57 @@
1
+ [
2
+ "droonga.message",
3
+ 0,
4
+ {
5
+ "inReplyTo": "request-id",
6
+ "statusCode": 200,
7
+ "type": "add.result",
8
+ "body": true
9
+ }
10
+ ]
11
+ [
12
+ "droonga.message",
13
+ 0,
14
+ {
15
+ "inReplyTo": "request-id",
16
+ "statusCode": 200,
17
+ "type": "add.result",
18
+ "body": true
19
+ }
20
+ ]
21
+ [
22
+ "droonga.message",
23
+ 0,
24
+ {
25
+ "inReplyTo": "request-id",
26
+ "statusCode": 200,
27
+ "type": "add.result",
28
+ "body": true
29
+ }
30
+ ]
31
+ [
32
+ "droonga.message",
33
+ 0,
34
+ {
35
+ "inReplyTo": "request-id",
36
+ "statusCode": 200,
37
+ "type": "search.result",
38
+ "body": {
39
+ "products": {
40
+ "records": [
41
+ [
42
+ "Groonga",
43
+ "groonga"
44
+ ],
45
+ [
46
+ "Rroonga",
47
+ "groonga"
48
+ ],
49
+ [
50
+ "Ruby",
51
+ "ruby"
52
+ ]
53
+ ]
54
+ }
55
+ }
56
+ }
57
+ ]