droonga-engine 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 (341) hide show
  1. data/.dir-locals.el +3 -0
  2. data/.gitignore +6 -0
  3. data/.travis.yml +15 -0
  4. data/.yardopts +7 -0
  5. data/Gemfile +66 -0
  6. data/LICENSE.txt +14 -0
  7. data/README.md +17 -0
  8. data/Rakefile +64 -0
  9. data/benchmark/benchmark.rb +123 -0
  10. data/benchmark/utils.rb +246 -0
  11. data/benchmark/watch/benchmark-notify.rb +143 -0
  12. data/benchmark/watch/benchmark-notify.sh +20 -0
  13. data/benchmark/watch/benchmark-publish.rb +120 -0
  14. data/benchmark/watch/benchmark-scan.rb +213 -0
  15. data/bin/droonga-catalog-generate +103 -0
  16. data/bin/droonga-engine +20 -0
  17. data/bin/droonga-engine-service +20 -0
  18. data/doc/text/news.md +106 -0
  19. data/droonga-engine.gemspec +52 -0
  20. data/lib/droonga/adapter.rb +48 -0
  21. data/lib/droonga/adapter_runner.rb +104 -0
  22. data/lib/droonga/catalog/base.rb +41 -0
  23. data/lib/droonga/catalog/collection_volume.rb +106 -0
  24. data/lib/droonga/catalog/dataset.rb +69 -0
  25. data/lib/droonga/catalog/errors.rb +113 -0
  26. data/lib/droonga/catalog/schema.rb +186 -0
  27. data/lib/droonga/catalog/single_volume.rb +28 -0
  28. data/lib/droonga/catalog/slice.rb +41 -0
  29. data/lib/droonga/catalog/version1.rb +427 -0
  30. data/lib/droonga/catalog/version2.rb +96 -0
  31. data/lib/droonga/catalog/version2_validator.rb +63 -0
  32. data/lib/droonga/catalog/volume.rb +33 -0
  33. data/lib/droonga/catalog/volume_collection.rb +56 -0
  34. data/lib/droonga/catalog_generator.rb +156 -0
  35. data/lib/droonga/catalog_loader.rb +56 -0
  36. data/lib/droonga/catalog_observer.rb +83 -0
  37. data/lib/droonga/collector.rb +38 -0
  38. data/lib/droonga/collector_message.rb +71 -0
  39. data/lib/droonga/collector_runner.rb +64 -0
  40. data/lib/droonga/collectors/and.rb +26 -0
  41. data/lib/droonga/collectors/or.rb +26 -0
  42. data/lib/droonga/collectors/sum.rb +26 -0
  43. data/lib/droonga/collectors.rb +18 -0
  44. data/lib/droonga/dispatcher.rb +326 -0
  45. data/lib/droonga/distributed_command_planner.rb +179 -0
  46. data/lib/droonga/distributor.rb +87 -0
  47. data/lib/droonga/engine/command/droonga_engine.rb +441 -0
  48. data/lib/droonga/engine/version.rb +20 -0
  49. data/lib/droonga/engine.rb +80 -0
  50. data/lib/droonga/engine_state.rb +79 -0
  51. data/lib/droonga/error.rb +73 -0
  52. data/lib/droonga/error_messages.rb +33 -0
  53. data/lib/droonga/event_loop.rb +46 -0
  54. data/lib/droonga/farm.rb +58 -0
  55. data/lib/droonga/fluent_message_receiver.rb +191 -0
  56. data/lib/droonga/fluent_message_sender.rb +140 -0
  57. data/lib/droonga/forwarder.rb +119 -0
  58. data/lib/droonga/handler.rb +49 -0
  59. data/lib/droonga/handler_message.rb +61 -0
  60. data/lib/droonga/handler_messenger.rb +119 -0
  61. data/lib/droonga/handler_runner.rb +125 -0
  62. data/lib/droonga/input_message.rb +51 -0
  63. data/lib/droonga/job_protocol.rb +20 -0
  64. data/lib/droonga/job_pusher.rb +179 -0
  65. data/lib/droonga/job_receiver.rb +70 -0
  66. data/lib/droonga/loggable.rb +29 -0
  67. data/lib/droonga/logger.rb +142 -0
  68. data/lib/droonga/message_matcher.rb +109 -0
  69. data/lib/droonga/output_message.rb +55 -0
  70. data/lib/droonga/planner.rb +47 -0
  71. data/lib/droonga/pluggable.rb +31 -0
  72. data/lib/droonga/plugin/metadata/adapter_input_message.rb +39 -0
  73. data/lib/droonga/plugin/metadata/adapter_output_message.rb +39 -0
  74. data/lib/droonga/plugin/metadata/collector_message.rb +39 -0
  75. data/lib/droonga/plugin/metadata/handler_action.rb +39 -0
  76. data/lib/droonga/plugin/metadata/input_message.rb +54 -0
  77. data/lib/droonga/plugin.rb +43 -0
  78. data/lib/droonga/plugin_loader.rb +63 -0
  79. data/lib/droonga/plugin_registry.rb +66 -0
  80. data/lib/droonga/plugins/basic.rb +54 -0
  81. data/lib/droonga/plugins/crud.rb +145 -0
  82. data/lib/droonga/plugins/dump.rb +97 -0
  83. data/lib/droonga/plugins/error.rb +51 -0
  84. data/lib/droonga/plugins/groonga/column_create.rb +123 -0
  85. data/lib/droonga/plugins/groonga/column_list.rb +124 -0
  86. data/lib/droonga/plugins/groonga/column_remove.rb +65 -0
  87. data/lib/droonga/plugins/groonga/column_rename.rb +67 -0
  88. data/lib/droonga/plugins/groonga/delete.rb +117 -0
  89. data/lib/droonga/plugins/groonga/generic_command.rb +105 -0
  90. data/lib/droonga/plugins/groonga/generic_response.rb +43 -0
  91. data/lib/droonga/plugins/groonga/select.rb +236 -0
  92. data/lib/droonga/plugins/groonga/table_create.rb +111 -0
  93. data/lib/droonga/plugins/groonga/table_list.rb +120 -0
  94. data/lib/droonga/plugins/groonga/table_remove.rb +57 -0
  95. data/lib/droonga/plugins/groonga.rb +37 -0
  96. data/lib/droonga/plugins/search/distributed_search_planner.rb +407 -0
  97. data/lib/droonga/plugins/search.rb +146 -0
  98. data/lib/droonga/plugins/watch.rb +178 -0
  99. data/lib/droonga/processor.rb +63 -0
  100. data/lib/droonga/reducer.rb +169 -0
  101. data/lib/droonga/replier.rb +49 -0
  102. data/lib/droonga/schema_applier.rb +167 -0
  103. data/lib/droonga/searcher/mecab_filter.rb +67 -0
  104. data/lib/droonga/searcher.rb +733 -0
  105. data/lib/droonga/server.rb +45 -0
  106. data/lib/droonga/session.rb +99 -0
  107. data/lib/droonga/single_step.rb +68 -0
  108. data/lib/droonga/single_step_definition.rb +54 -0
  109. data/lib/droonga/slice.rb +122 -0
  110. data/lib/droonga/status_code.rb +25 -0
  111. data/lib/droonga/step_runner.rb +64 -0
  112. data/lib/droonga/sweeper.rb +42 -0
  113. data/lib/droonga/test/stub_handler.rb +37 -0
  114. data/lib/droonga/test/stub_handler_message.rb +35 -0
  115. data/lib/droonga/test/stub_handler_messenger.rb +34 -0
  116. data/lib/droonga/test/stub_planner.rb +31 -0
  117. data/lib/droonga/test.rb +21 -0
  118. data/lib/droonga/watch_schema.rb +92 -0
  119. data/lib/droonga/watcher.rb +257 -0
  120. data/lib/droonga/worker.rb +61 -0
  121. data/sample/cluster/catalog.json +42 -0
  122. data/sample/mecab_filter/data.grn +7 -0
  123. data/sample/mecab_filter/ddl.grn +7 -0
  124. data/sample/mecab_filter/search_with_mecab_filter.json +21 -0
  125. data/sample/mecab_filter/search_without_mecab_filter.json +21 -0
  126. data/test/command/config/default/catalog.json +85 -0
  127. data/test/command/config/default/fluentd.conf +11 -0
  128. data/test/command/config/version1/catalog.json +68 -0
  129. data/test/command/config/version1/fluentd.conf +11 -0
  130. data/test/command/fixture/documents.jsons +208 -0
  131. data/test/command/fixture/event.jsons +41 -0
  132. data/test/command/fixture/user-table-array.jsons +38 -0
  133. data/test/command/fixture/user-table.jsons +47 -0
  134. data/test/command/run-test.rb +34 -0
  135. data/test/command/suite/add/dimension/column.catalog.json +28 -0
  136. data/test/command/suite/add/dimension/column.expected +41 -0
  137. data/test/command/suite/add/dimension/column.test +51 -0
  138. data/test/command/suite/add/dimension/integer.catalog.json +19 -0
  139. data/test/command/suite/add/dimension/integer.expected +41 -0
  140. data/test/command/suite/add/dimension/integer.test +51 -0
  141. data/test/command/suite/add/error/invalid-integer.expected +46 -0
  142. data/test/command/suite/add/error/invalid-integer.test +12 -0
  143. data/test/command/suite/add/error/invalid-time.expected +46 -0
  144. data/test/command/suite/add/error/invalid-time.test +12 -0
  145. data/test/command/suite/add/error/missing-key.expected +25 -0
  146. data/test/command/suite/add/error/missing-key.test +16 -0
  147. data/test/command/suite/add/error/missing-table.expected +25 -0
  148. data/test/command/suite/add/error/missing-table.test +16 -0
  149. data/test/command/suite/add/error/unknown-column.expected +46 -0
  150. data/test/command/suite/add/error/unknown-column.test +12 -0
  151. data/test/command/suite/add/error/unknown-table.expected +25 -0
  152. data/test/command/suite/add/error/unknown-table.test +17 -0
  153. data/test/command/suite/add/minimum.expected +6 -0
  154. data/test/command/suite/add/minimum.test +11 -0
  155. data/test/command/suite/add/with-values.expected +6 -0
  156. data/test/command/suite/add/with-values.test +17 -0
  157. data/test/command/suite/add/without-key.expected +6 -0
  158. data/test/command/suite/add/without-key.test +16 -0
  159. data/test/command/suite/groonga/column_create/scalar.expected +26 -0
  160. data/test/command/suite/groonga/column_create/scalar.test +17 -0
  161. data/test/command/suite/groonga/column_create/unknown-table.expected +14 -0
  162. data/test/command/suite/groonga/column_create/unknown-table.test +7 -0
  163. data/test/command/suite/groonga/column_create/vector.expected +26 -0
  164. data/test/command/suite/groonga/column_create/vector.test +18 -0
  165. data/test/command/suite/groonga/column_list/success.expected +86 -0
  166. data/test/command/suite/groonga/column_list/success.test +24 -0
  167. data/test/command/suite/groonga/column_list/unknown-table.expected +13 -0
  168. data/test/command/suite/groonga/column_list/unknown-table.test +7 -0
  169. data/test/command/suite/groonga/column_remove/success.expected +39 -0
  170. data/test/command/suite/groonga/column_remove/success.test +25 -0
  171. data/test/command/suite/groonga/column_remove/unknown-column.expected +27 -0
  172. data/test/command/suite/groonga/column_remove/unknown-column.test +16 -0
  173. data/test/command/suite/groonga/column_remove/unknown-table.expected +14 -0
  174. data/test/command/suite/groonga/column_remove/unknown-table.test +7 -0
  175. data/test/command/suite/groonga/column_rename/success.expected +39 -0
  176. data/test/command/suite/groonga/column_rename/success.test +26 -0
  177. data/test/command/suite/groonga/column_rename/unknown-column.expected +27 -0
  178. data/test/command/suite/groonga/column_rename/unknown-column.test +16 -0
  179. data/test/command/suite/groonga/column_rename/unknown-table.expected +14 -0
  180. data/test/command/suite/groonga/column_rename/unknown-table.test +7 -0
  181. data/test/command/suite/groonga/delete/duplicated-identifiers.expected +27 -0
  182. data/test/command/suite/groonga/delete/duplicated-identifiers.test +17 -0
  183. data/test/command/suite/groonga/delete/filter.expected +19 -0
  184. data/test/command/suite/groonga/delete/filter.test +19 -0
  185. data/test/command/suite/groonga/delete/invalid-filter.expected +14 -0
  186. data/test/command/suite/groonga/delete/invalid-filter.test +9 -0
  187. data/test/command/suite/groonga/delete/no-identifier.expected +27 -0
  188. data/test/command/suite/groonga/delete/no-identifier.test +15 -0
  189. data/test/command/suite/groonga/delete/success.expected +19 -0
  190. data/test/command/suite/groonga/delete/success.test +19 -0
  191. data/test/command/suite/groonga/delete/unknown-table.expected +14 -0
  192. data/test/command/suite/groonga/delete/unknown-table.test +7 -0
  193. data/test/command/suite/groonga/select/minimum.expected +22 -0
  194. data/test/command/suite/groonga/select/minimum.test +8 -0
  195. data/test/command/suite/groonga/table_create/array.expected +14 -0
  196. data/test/command/suite/groonga/table_create/array.test +8 -0
  197. data/test/command/suite/groonga/table_create/hash.expected +13 -0
  198. data/test/command/suite/groonga/table_create/hash.test +8 -0
  199. data/test/command/suite/groonga/table_list/success.expected +71 -0
  200. data/test/command/suite/groonga/table_list/success.test +15 -0
  201. data/test/command/suite/groonga/table_remove/success.expected +13 -0
  202. data/test/command/suite/groonga/table_remove/success.test +8 -0
  203. data/test/command/suite/groonga/table_remove/unknown-table.expected +14 -0
  204. data/test/command/suite/groonga/table_remove/unknown-table.test +7 -0
  205. data/test/command/suite/message/error/missing-dataset.expected +9 -0
  206. data/test/command/suite/message/error/missing-dataset.test +5 -0
  207. data/test/command/suite/message/error/unknown-dataset.expected +9 -0
  208. data/test/command/suite/message/error/unknown-dataset.test +6 -0
  209. data/test/command/suite/message/error/unknown-type.expected +9 -0
  210. data/test/command/suite/message/error/unknown-type.test +6 -0
  211. data/test/command/suite/search/adjusters/multiple.catalog.json +38 -0
  212. data/test/command/suite/search/adjusters/multiple.expected +19 -0
  213. data/test/command/suite/search/adjusters/multiple.test +75 -0
  214. data/test/command/suite/search/adjusters/one.catalog.json +38 -0
  215. data/test/command/suite/search/adjusters/one.expected +19 -0
  216. data/test/command/suite/search/adjusters/one.test +66 -0
  217. data/test/command/suite/search/attributes/array.expected +21 -0
  218. data/test/command/suite/search/attributes/array.test +28 -0
  219. data/test/command/suite/search/attributes/hash.expected +30 -0
  220. data/test/command/suite/search/attributes/hash.test +36 -0
  221. data/test/command/suite/search/complex.expected +48 -0
  222. data/test/command/suite/search/complex.test +23 -0
  223. data/test/command/suite/search/condition/nested.expected +15 -0
  224. data/test/command/suite/search/condition/nested.test +27 -0
  225. data/test/command/suite/search/condition/query/nonexistent_column.catalog.json +37 -0
  226. data/test/command/suite/search/condition/query/nonexistent_column.expected +48 -0
  227. data/test/command/suite/search/condition/query/nonexistent_column.test +33 -0
  228. data/test/command/suite/search/condition/query/syntax_error.catalog.json +36 -0
  229. data/test/command/suite/search/condition/query/syntax_error.expected +48 -0
  230. data/test/command/suite/search/condition/query/syntax_error.test +33 -0
  231. data/test/command/suite/search/condition/query.expected +24 -0
  232. data/test/command/suite/search/condition/query.test +23 -0
  233. data/test/command/suite/search/condition/script.expected +24 -0
  234. data/test/command/suite/search/condition/script.test +26 -0
  235. data/test/command/suite/search/error/cyclic-source.expected +14 -0
  236. data/test/command/suite/search/error/cyclic-source.test +12 -0
  237. data/test/command/suite/search/error/deeply-cyclic-source.expected +17 -0
  238. data/test/command/suite/search/error/deeply-cyclic-source.test +15 -0
  239. data/test/command/suite/search/error/missing-source-parameter.expected +13 -0
  240. data/test/command/suite/search/error/missing-source-parameter.test +11 -0
  241. data/test/command/suite/search/error/no-query.expected +9 -0
  242. data/test/command/suite/search/error/no-query.test +7 -0
  243. data/test/command/suite/search/error/unknown-source.expected +52 -0
  244. data/test/command/suite/search/error/unknown-source.test +12 -0
  245. data/test/command/suite/search/group/count.expected +10 -0
  246. data/test/command/suite/search/group/count.test +18 -0
  247. data/test/command/suite/search/group/limit.expected +15 -0
  248. data/test/command/suite/search/group/limit.test +20 -0
  249. data/test/command/suite/search/group/string.expected +32 -0
  250. data/test/command/suite/search/group/string.test +40 -0
  251. data/test/command/suite/search/group/subrecord/with-sort.catalog.json +33 -0
  252. data/test/command/suite/search/group/subrecord/with-sort.expected +30 -0
  253. data/test/command/suite/search/group/subrecord/with-sort.test +81 -0
  254. data/test/command/suite/search/multiple/chained.expected +41 -0
  255. data/test/command/suite/search/multiple/chained.test +39 -0
  256. data/test/command/suite/search/multiple/parallel.expected +35 -0
  257. data/test/command/suite/search/multiple/parallel.test +35 -0
  258. data/test/command/suite/search/output/attributes/invalid.catalog.json +13 -0
  259. data/test/command/suite/search/output/attributes/invalid.expected +44 -0
  260. data/test/command/suite/search/output/attributes/invalid.test +28 -0
  261. data/test/command/suite/search/range/only-output.expected +24 -0
  262. data/test/command/suite/search/range/only-output.test +23 -0
  263. data/test/command/suite/search/range/only-sort.expected +24 -0
  264. data/test/command/suite/search/range/only-sort.test +26 -0
  265. data/test/command/suite/search/range/sort-and-output.expected +21 -0
  266. data/test/command/suite/search/range/sort-and-output.test +27 -0
  267. data/test/command/suite/search/range/too-large-output-offset.expected +12 -0
  268. data/test/command/suite/search/range/too-large-output-offset.test +23 -0
  269. data/test/command/suite/search/range/too-large-sort-offset.expected +12 -0
  270. data/test/command/suite/search/range/too-large-sort-offset.test +26 -0
  271. data/test/command/suite/search/response/elapsed_time.catalog.json +13 -0
  272. data/test/command/suite/search/response/elapsed_time.expected +11 -0
  273. data/test/command/suite/search/response/elapsed_time.test +26 -0
  274. data/test/command/suite/search/response/records/value/time.expected +20 -0
  275. data/test/command/suite/search/response/records/value/time.test +22 -0
  276. data/test/command/suite/search/simple.expected +48 -0
  277. data/test/command/suite/search/simple.test +22 -0
  278. data/test/command/suite/search/sort/default-offset-limit.expected +39 -0
  279. data/test/command/suite/search/sort/default-offset-limit.test +24 -0
  280. data/test/command/suite/search/sort/invisible-column.expected +24 -0
  281. data/test/command/suite/search/sort/invisible-column.test +26 -0
  282. data/test/command/suite/watch/subscribe.expected +6 -0
  283. data/test/command/suite/watch/subscribe.test +9 -0
  284. data/test/command/suite/watch/unsubscribe.expected +6 -0
  285. data/test/command/suite/watch/unsubscribe.test +9 -0
  286. data/test/performance/run-test.rb +56 -0
  287. data/test/performance/watch/catalog.json +33 -0
  288. data/test/performance/watch/feed.json +9 -0
  289. data/test/performance/watch/fluentd.conf +11 -0
  290. data/test/performance/watch/subscribe.json +3 -0
  291. data/test/unit/catalog/test_collection_volume.rb +103 -0
  292. data/test/unit/catalog/test_dataset.rb +104 -0
  293. data/test/unit/catalog/test_schema.rb +226 -0
  294. data/test/unit/catalog/test_single_volume.rb +31 -0
  295. data/test/unit/catalog/test_slice.rb +92 -0
  296. data/test/unit/catalog/test_version1.rb +361 -0
  297. data/test/unit/catalog/test_version2.rb +124 -0
  298. data/test/unit/catalog/test_version2_validator.rb +66 -0
  299. data/test/unit/catalog/test_volume_collection.rb +50 -0
  300. data/test/unit/fixtures/array.grn +18 -0
  301. data/test/unit/fixtures/catalog/version1.json +40 -0
  302. data/test/unit/fixtures/catalog/version2.json +62 -0
  303. data/test/unit/fixtures/document.grn +34 -0
  304. data/test/unit/fixtures/reference/array.grn +11 -0
  305. data/test/unit/fixtures/reference/hash.grn +7 -0
  306. data/test/unit/helper/distributed_search_planner_helper.rb +83 -0
  307. data/test/unit/helper/fixture.rb +28 -0
  308. data/test/unit/helper/plugin_helper.rb +38 -0
  309. data/test/unit/helper/sandbox.rb +86 -0
  310. data/test/unit/helper/stub_worker.rb +27 -0
  311. data/test/unit/helper/watch_helper.rb +23 -0
  312. data/test/unit/helper.rb +28 -0
  313. data/test/unit/plugins/crud/test_add.rb +190 -0
  314. data/test/unit/plugins/groonga/select/test_adapter_input.rb +510 -0
  315. data/test/unit/plugins/groonga/select/test_adapter_output.rb +201 -0
  316. data/test/unit/plugins/groonga/test_column_create.rb +171 -0
  317. data/test/unit/plugins/groonga/test_column_list.rb +170 -0
  318. data/test/unit/plugins/groonga/test_column_remove.rb +98 -0
  319. data/test/unit/plugins/groonga/test_column_rename.rb +105 -0
  320. data/test/unit/plugins/groonga/test_delete.rb +127 -0
  321. data/test/unit/plugins/groonga/test_table_create.rb +147 -0
  322. data/test/unit/plugins/groonga/test_table_list.rb +184 -0
  323. data/test/unit/plugins/groonga/test_table_remove.rb +61 -0
  324. data/test/unit/plugins/search/planner/test_basic.rb +120 -0
  325. data/test/unit/plugins/search/planner/test_group_by.rb +573 -0
  326. data/test/unit/plugins/search/planner/test_output.rb +388 -0
  327. data/test/unit/plugins/search/planner/test_sort_by.rb +938 -0
  328. data/test/unit/plugins/search/test_collector.rb +806 -0
  329. data/test/unit/plugins/search/test_handler.rb +930 -0
  330. data/test/unit/plugins/search/test_planner.rb +174 -0
  331. data/test/unit/plugins/test_basic.rb +510 -0
  332. data/test/unit/plugins/test_groonga.rb +70 -0
  333. data/test/unit/plugins/test_watch.rb +211 -0
  334. data/test/unit/run-test.rb +56 -0
  335. data/test/unit/test_catalog_generator.rb +93 -0
  336. data/test/unit/test_message_matcher.rb +160 -0
  337. data/test/unit/test_schema_applier.rb +59 -0
  338. data/test/unit/test_sweeper.rb +95 -0
  339. data/test/unit/test_watch_schema.rb +57 -0
  340. data/test/unit/test_watcher.rb +336 -0
  341. metadata +759 -0
@@ -0,0 +1,92 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2013 Droonga Project
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License version 2.1 as published by the Free Software Foundation.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+
18
+ require "groonga"
19
+
20
+ require "droonga/loggable"
21
+
22
+ module Droonga
23
+ class WatchSchema
24
+ include Loggable
25
+
26
+ def initialize(context)
27
+ @context = context
28
+ end
29
+
30
+ def ensure_created
31
+ if @context["Keyword"]
32
+ logger.trace("skip table creation")
33
+ return
34
+ end
35
+ logger.trace("ensure_tables: start")
36
+ ensure_tables
37
+ logger.trace("ensure_tables: done")
38
+ end
39
+
40
+ private
41
+ def ensure_tables
42
+ Groonga::Schema.define(:context => @context) do |schema|
43
+ schema.create_table("Keyword",
44
+ :type => :patricia_trie,
45
+ :key_type => "ShortText",
46
+ :key_normalize => true,
47
+ :force => true) do |table|
48
+ end
49
+
50
+ schema.create_table("Query",
51
+ :type => :hash,
52
+ :key_type => "ShortText",
53
+ :force => true) do |table|
54
+ end
55
+
56
+ schema.create_table("Route",
57
+ :type => :hash,
58
+ :key_type => "ShortText",
59
+ :force => true) do |table|
60
+ end
61
+
62
+ schema.create_table("Subscriber",
63
+ :type => :hash,
64
+ :key_type => "ShortText",
65
+ :force => true) do |table|
66
+ table.time("last_modified")
67
+ end
68
+
69
+ schema.change_table("Query") do |table|
70
+ table.reference("keywords", "Keyword", :type => :vector)
71
+ end
72
+
73
+ schema.change_table("Subscriber") do |table|
74
+ table.reference("route", "Route")
75
+ table.reference("subscriptions", "Query", :type => :vector)
76
+ end
77
+
78
+ schema.change_table("Keyword") do |table|
79
+ table.index("Query", "keywords", :name => "queries")
80
+ end
81
+
82
+ schema.change_table("Query") do |table|
83
+ table.index("Subscriber", "subscriptions", :name => "subscribers")
84
+ end
85
+ end
86
+ end
87
+
88
+ def log_tag
89
+ "[#{Process.ppid}][#{Process.pid}] watch_schema"
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,257 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2013 Droonga Project
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License version 2.1 as published by the Free Software Foundation.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+
18
+ module Droonga
19
+ class Watcher
20
+ EXACT_MATCH = false
21
+
22
+ def initialize(context)
23
+ @context = context
24
+
25
+ @subscriber_table = @context["Subscriber"]
26
+ @query_table = @context["Query"]
27
+ @keyword_table = @context["Keyword"]
28
+ end
29
+
30
+ def subscribe(request)
31
+ subscriber = request[:subscriber]
32
+ condition = request[:condition]
33
+ query = request[:query]
34
+ route = request[:route]
35
+
36
+ # XXX better validation and error class must be written!!
37
+ if subscriber.nil? or subscriber.empty? or condition.nil? or
38
+ query.nil? or route.nil?
39
+ raise "invalid request"
40
+ end
41
+ raise "too long query" if query.size > 4095
42
+
43
+ query_record = @query_table[query]
44
+ unless query_record
45
+ keywords = pick_keywords([], condition)
46
+ query_record = @query_table.add(query, :keywords => keywords)
47
+ end
48
+ subscriber_record = @subscriber_table[subscriber]
49
+ if subscriber_record
50
+ subscriptions = subscriber_record.subscriptions
51
+ unless subscriptions.include?(query_record)
52
+ subscriptions << query_record
53
+ subscriber_record.subscriptions = subscriptions
54
+ end
55
+ subscriber_record.last_modified = Time.now
56
+ else
57
+ @subscriber_table.add(subscriber,
58
+ :subscriptions => [query_record],
59
+ :route => route,
60
+ :last_modified => Time.now)
61
+ end
62
+ end
63
+
64
+ def unsubscribe(request)
65
+ subscriber = request[:subscriber]
66
+ query = request[:query]
67
+
68
+ if subscriber.nil? or subscriber.empty?
69
+ raise "invalid request"
70
+ end
71
+
72
+ subscriber_record = @subscriber_table[subscriber]
73
+ return unless subscriber_record
74
+
75
+ if query.nil? or query.empty?
76
+ delete_subscriber(subscriber_record)
77
+ else
78
+ query_record = @query_table[query]
79
+ return unless query_record
80
+
81
+ subscriptions = subscriber_record.subscriptions
82
+ new_subscriptions = subscriptions.select do |subscription|
83
+ subscription != query_record
84
+ end
85
+
86
+ if new_subscriptions.empty?
87
+ delete_subscriber(subscriber_record)
88
+ else
89
+ subscriber_record.subscriptions = new_subscriptions
90
+ sweep_orphan_queries(subscriptions)
91
+ end
92
+ end
93
+ end
94
+
95
+ def feed(request, &block)
96
+ targets = request[:targets]
97
+
98
+ hits = []
99
+ targets.each do |key, target|
100
+ scan_body(hits, target)
101
+ end
102
+ hits.uniq! # hits may be duplicated if multiple targets are matched
103
+
104
+ publish(hits, request, &block)
105
+ end
106
+
107
+ def pick_keywords(memo, condition)
108
+ case condition
109
+ when Hash
110
+ memo << condition["query"]
111
+ when String
112
+ memo << condition
113
+ when Array
114
+ condition[1..-1].each do |element|
115
+ pick_keywords(memo, element)
116
+ end
117
+ end
118
+ memo
119
+ end
120
+
121
+ def scan_body(hits, body)
122
+ trimmed = body.strip
123
+ candidates = {}
124
+ # FIXME scan reports the longest keyword matched only
125
+ @keyword_table.scan(trimmed).each do |keyword, word, start, length|
126
+ @query_table.select do |query|
127
+ query.keywords =~ keyword
128
+ end.each do |record|
129
+ candidates[record.key] ||= []
130
+ candidates[record.key] << keyword
131
+ end
132
+ end
133
+ candidates.each do |query, keywords|
134
+ hits << query if query_match(query, keywords)
135
+ end
136
+ end
137
+
138
+ def query_match(query, keywords)
139
+ return true unless EXACT_MATCH
140
+ @conditions = {} unless @conditions
141
+ condition = @conditions[query.id]
142
+ unless condition
143
+ condition = JSON.parse(query.key)
144
+ @conditions[query.id] = condition
145
+ # CAUTION: @conditions can be huge.
146
+ end
147
+ words = {}
148
+ keywords.each do |keyword|
149
+ words[keyword.key] = true
150
+ end
151
+ eval_condition(condition, words)
152
+ end
153
+
154
+ def eval_condition(condition, words)
155
+ case condition
156
+ when Hash
157
+ # todo
158
+ when String
159
+ words[condition]
160
+ when Array
161
+ case condition.first
162
+ when "||"
163
+ condition[1..-1].each do |element|
164
+ return true if eval_condition(element, words)
165
+ end
166
+ false
167
+ when "&&"
168
+ condition[1..-1].each do |element|
169
+ return false unless eval_condition(element, words)
170
+ end
171
+ true
172
+ when "-"
173
+ return false unless eval_condition(condition[1], words)
174
+ condition[2..-1].each do |element|
175
+ return false if eval_condition(element, words)
176
+ end
177
+ true
178
+ end
179
+ end
180
+ end
181
+
182
+ def publish(hits, request)
183
+ routes = {}
184
+ hits.each do |query|
185
+ subscribers = @subscriber_table.select do |subscriber|
186
+ subscriber.subscriptions =~ query
187
+ end
188
+ subscribers.each do |subscriber|
189
+ route = subscriber.route.key
190
+ routes[route] ||= []
191
+ routes[route] << subscriber.key.key
192
+ end
193
+ =begin
194
+ # "group" version. This is slower than above...
195
+ route_records = subscribers.group("route",
196
+ :max_n_sub_records => subscribers.size)
197
+ route_records.each do |route_record|
198
+ route = route_record._key
199
+ routes[route] ||= []
200
+ route_record.sub_records.each do |subscriber|
201
+ routes[route] << subscriber.key.key
202
+ end
203
+ end
204
+ =end
205
+ end
206
+ routes.each do |route, subscribers|
207
+ yield(route, subscribers)
208
+ end
209
+ end
210
+
211
+ private
212
+ def delete_subscriber(subscriber)
213
+ queries = subscriber.subscriptions
214
+ route = subscriber.route
215
+ subscriber.delete
216
+ sweep_orphan_queries(queries)
217
+ sweep_orphan_route(route)
218
+ end
219
+
220
+ def delete_query(query)
221
+ keywords = query.keywords
222
+ query.delete
223
+ sweep_orphan_keywords(keywords)
224
+ end
225
+
226
+ def sweep_orphan_queries(queries)
227
+ queries.each do |query|
228
+ related_subscribers = @subscriber_table.select do |subscriber|
229
+ subscriber.subscriptions =~ query
230
+ end
231
+ if related_subscribers.empty?
232
+ delete_query(query)
233
+ end
234
+ end
235
+ end
236
+
237
+ def sweep_orphan_keywords(keywords)
238
+ keywords.each do |keyword|
239
+ related_queries = @query_table.select do |query|
240
+ query.keywords =~ keyword
241
+ end
242
+ if related_queries.empty?
243
+ keyword.delete
244
+ end
245
+ end
246
+ end
247
+
248
+ def sweep_orphan_route(route)
249
+ related_subscribers = @subscriber_table.select do |subscriber|
250
+ subscriber.route == route
251
+ end
252
+ if related_subscribers.empty?
253
+ route.delete
254
+ end
255
+ end
256
+ end
257
+ end
@@ -0,0 +1,61 @@
1
+ # Copyright (C) 2013-2014 Droonga Project
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License version 2.1 as published by the Free Software Foundation.
6
+ #
7
+ # This library is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
+ # Lesser General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU Lesser General Public
13
+ # License along with this library; if not, write to the Free Software
14
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
+
16
+ require "droonga/event_loop"
17
+ require "droonga/handler_runner"
18
+ require "droonga/job_receiver"
19
+
20
+ module Droonga
21
+ module Worker
22
+ def initialize
23
+ @raw_loop = Coolio::Loop.new
24
+ @loop = EventLoop.new(@raw_loop)
25
+ @handler_runner = HandlerRunner.new(@loop,
26
+ config.merge(:dispatcher => nil))
27
+ receive_socket_path = config[:job_receive_socket_path]
28
+ @job_receiver = JobReceiver.new(@loop, receive_socket_path) do |message|
29
+ process(message)
30
+ end
31
+ end
32
+
33
+ def run
34
+ Droonga.logger.trace("#{log_tag}: run: start")
35
+ @handler_runner.start
36
+ @job_receiver.start
37
+ @raw_loop.run
38
+ @handler_runner.shutdown
39
+ Droonga.logger.trace("#{log_tag}: run: done")
40
+ end
41
+
42
+ def stop
43
+ Droonga.logger.trace("#{log_tag}: stop: start")
44
+ @job_receiver.shutdown
45
+ @raw_loop.stop
46
+ @loop.break_current_loop
47
+ Droonga.logger.trace("#{log_tag}: stop: done")
48
+ end
49
+
50
+ private
51
+ def process(message)
52
+ Droonga.logger.trace("#{log_tag}: process: start")
53
+ @handler_runner.process(message)
54
+ Droonga.logger.trace("#{log_tag}: process: done")
55
+ end
56
+
57
+ def log_tag
58
+ "[#{Process.ppid}][#{Process.pid}] worker"
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,42 @@
1
+ {
2
+ "version": 2,
3
+ "effectiveDate": "2013-09-01T00:00:00Z",
4
+ "datasets": {
5
+ "Droonga": {
6
+ "nWorkers": 2,
7
+ "plugins": ["groonga", "search", "crud"],
8
+ "schema": {
9
+ },
10
+ "replicas": [
11
+ {
12
+ "slices": [
13
+ {
14
+ "volume": {
15
+ "address": "127.0.0.1:10031/droonga.000"
16
+ }
17
+ },
18
+ {
19
+ "volume": {
20
+ "address": "127.0.0.1:10031/droonga.001"
21
+ }
22
+ }
23
+ ]
24
+ },
25
+ {
26
+ "slices": [
27
+ {
28
+ "volume": {
29
+ "address": "127.0.0.1:10031/droonga.010"
30
+ }
31
+ },
32
+ {
33
+ "volume": {
34
+ "address": "127.0.0.1:10031/droonga.011"
35
+ }
36
+ }
37
+ ]
38
+ }
39
+ ]
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,7 @@
1
+ load --table Memo
2
+ [
3
+ {"_key": "1", "content": "アンパサンド"},
4
+ {"_key": "2", "content": "ジャパン"},
5
+ {"_key": "3", "content": "食パン"},
6
+ {"_key": "4", "content": "フランスのパン"}
7
+ ]
@@ -0,0 +1,7 @@
1
+ table_create Memo TABLE_HASH_KEY ShortText
2
+ column_create Memo content COLUMN_SCALAR ShortText
3
+
4
+ table_create Terms TABLE_PAT_KEY ShortText \
5
+ --default_tokenizer TokenBigram \
6
+ --normalizer NormalizerAuto
7
+ column_create Terms memo_context COLUMN_INDEX|WITH_POSITION Memo content
@@ -0,0 +1,21 @@
1
+ {
2
+ "type": "search",
3
+ "dataset": "Droonga",
4
+ "body": {
5
+ "queries": {
6
+ "search": {
7
+ "source": "Memo",
8
+ "condition": {
9
+ "matchTo": ["content"],
10
+ "query": "パン",
11
+ "useMeCabFilter": true
12
+ },
13
+ "output": {
14
+ "elements": ["count", "records"],
15
+ "attributes": ["_key", "content"],
16
+ "limit": 10
17
+ }
18
+ }
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "type": "search",
3
+ "dataset": "Droonga",
4
+ "body": {
5
+ "queries": {
6
+ "search": {
7
+ "source": "Memo",
8
+ "condition": {
9
+ "matchTo": ["content"],
10
+ "query": "パン",
11
+ "useMeCabFilter": false
12
+ },
13
+ "output": {
14
+ "elements": ["count", "records"],
15
+ "attributes": ["_key", "content"],
16
+ "limit": 10
17
+ }
18
+ }
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,85 @@
1
+ {
2
+ "version": 2,
3
+ "effectiveDate": "2014-02-28T00:00:00Z",
4
+ "datasets": {
5
+ "Droonga": {
6
+ "nWorkers": 4,
7
+ "plugins": ["groonga", "crud", "search"],
8
+ "replicas": [
9
+ {
10
+ "dimension": "_key",
11
+ "slicer": "hash",
12
+ "slices": [
13
+ {
14
+ "label": "slice000",
15
+ "weight": 50,
16
+ "volume": {
17
+ "address": "127.0.0.1:23003/droonga.000"
18
+ }
19
+ },
20
+ {
21
+ "label": "slice001",
22
+ "weight": 50,
23
+ "volume": {
24
+ "address": "127.0.0.1:23003/droonga.001"
25
+ }
26
+ },
27
+ {
28
+ "label": "slice002",
29
+ "weight": 50,
30
+ "volume": {
31
+ "address": "127.0.0.1:23003/droonga.002"
32
+ }
33
+ }
34
+ ]
35
+ },
36
+ {
37
+ "dimension": "_key",
38
+ "slicer": "hash",
39
+ "slices": [
40
+ {
41
+ "label": "slice010",
42
+ "weight": 50,
43
+ "volume": {
44
+ "address": "127.0.0.1:23003/droonga.010"
45
+ }
46
+ },
47
+ {
48
+ "label": "slice011",
49
+ "weight": 50,
50
+ "volume": {
51
+ "address": "127.0.0.1:23003/droonga.011"
52
+ }
53
+ },
54
+ {
55
+ "label": "slice012",
56
+ "weight": 50,
57
+ "volume": {
58
+ "address": "127.0.0.1:23003/droonga.012"
59
+ }
60
+ }
61
+ ]
62
+ }
63
+ ]
64
+ },
65
+ "Watch": {
66
+ "nWorkers": 4,
67
+ "plugins": ["groonga", "watch", "search", "crud"],
68
+ "replicas": [
69
+ {
70
+ "dimension": "_key",
71
+ "slicer": "hash",
72
+ "slices": [
73
+ {
74
+ "label": "slice100",
75
+ "weight": 50,
76
+ "volume": {
77
+ "address": "127.0.0.1:23003/droonga.watch"
78
+ }
79
+ }
80
+ ]
81
+ }
82
+ ]
83
+ }
84
+ }
85
+ }
@@ -0,0 +1,11 @@
1
+ <source>
2
+ type forward
3
+ port 23003
4
+ </source>
5
+ <match droonga.message>
6
+ name 127.0.0.1:23003/droonga
7
+ type droonga
8
+ </match>
9
+ <match output.message>
10
+ type stdout
11
+ </match>
@@ -0,0 +1,68 @@
1
+ {
2
+ "version": 1,
3
+ "effective_date": "2013-09-01T00:00:00Z",
4
+ "zones": ["127.0.0.1:23003/droonga"],
5
+ "farms": {
6
+ "127.0.0.1:23003/droonga": {
7
+ "device": ".",
8
+ "capacity": 10
9
+ }
10
+ },
11
+ "datasets": {
12
+ "Droonga": {
13
+ "workers": 4,
14
+ "plugins": ["groonga", "crud", "search"],
15
+ "number_of_replicas": 2,
16
+ "number_of_partitions": 3,
17
+ "partition_key": "_key",
18
+ "date_range": "infinity",
19
+ "ring": {
20
+ "127.0.0.1:23041": {
21
+ "weight": 50,
22
+ "partitions": {
23
+ "2013-09-01": [
24
+ "127.0.0.1:23003/droonga.000",
25
+ "127.0.0.1:23003/droonga.001"
26
+ ]
27
+ }
28
+ },
29
+ "127.0.0.1:23042": {
30
+ "weight": 50,
31
+ "partitions": {
32
+ "2013-09-01": [
33
+ "127.0.0.1:23003/droonga.010",
34
+ "127.0.0.1:23003/droonga.011"
35
+ ]
36
+ }
37
+ },
38
+ "127.0.0.1:23043": {
39
+ "weight": 50,
40
+ "partitions": {
41
+ "2013-09-01": [
42
+ "127.0.0.1:23003/droonga.020",
43
+ "127.0.0.1:23003/droonga.021"
44
+ ]
45
+ }
46
+ }
47
+ }
48
+ },
49
+ "Watch": {
50
+ "workers": 4,
51
+ "plugins": ["groonga", "watch", "search", "crud"],
52
+ "number_of_replicas": 1,
53
+ "number_of_partitions": 1,
54
+ "partition_key": "_key",
55
+ "date_range": "infinity",
56
+ "ring": {
57
+ "127.0.0.1:23041": {
58
+ "weight": 50,
59
+ "partitions": {
60
+ "2013-09-01": [
61
+ "127.0.0.1:23003/droonga.watch"
62
+ ]
63
+ }
64
+ }
65
+ }
66
+ }
67
+ }
68
+ }
@@ -0,0 +1,11 @@
1
+ <source>
2
+ type forward
3
+ port 23003
4
+ </source>
5
+ <match droonga.message>
6
+ name 127.0.0.1:23003/droonga
7
+ type droonga
8
+ </match>
9
+ <match output.message>
10
+ type stdout
11
+ </match>