picky 1.4.1 → 1.4.2

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 (229) hide show
  1. data/lib/picky/{alias_instances.rb → aliases.rb} +1 -3
  2. data/lib/picky/application.rb +18 -19
  3. data/lib/picky/cores.rb +1 -1
  4. data/lib/picky/generators/aliases.rb +3 -0
  5. data/lib/picky/index/base.rb +179 -0
  6. data/lib/picky/index/memory.rb +28 -0
  7. data/lib/picky/index/redis.rb +28 -0
  8. data/lib/picky/{indexes_api.rb → index_bundle.rb} +16 -16
  9. data/lib/picky/indexed/indexes.rb +11 -7
  10. data/lib/picky/indexing/indexes.rb +14 -8
  11. data/lib/picky/internals/adapters/rack/base.rb +27 -0
  12. data/lib/picky/internals/adapters/rack/live_parameters.rb +37 -0
  13. data/lib/picky/internals/adapters/rack/query.rb +63 -0
  14. data/lib/picky/internals/adapters/rack.rb +34 -0
  15. data/lib/picky/{calculations → internals/calculations}/location.rb +0 -0
  16. data/lib/picky/{cli.rb → internals/cli.rb} +0 -0
  17. data/lib/picky/{configuration → internals/configuration}/index.rb +8 -2
  18. data/lib/picky/{ext → internals/ext}/maybe_compile.rb +0 -0
  19. data/lib/picky/{ext → internals/ext}/ruby19/extconf.rb +0 -0
  20. data/lib/picky/{ext → internals/ext}/ruby19/performant.c +0 -0
  21. data/lib/picky/{extensions → internals/extensions}/array.rb +0 -0
  22. data/lib/picky/{extensions → internals/extensions}/hash.rb +0 -0
  23. data/lib/picky/{extensions → internals/extensions}/module.rb +0 -0
  24. data/lib/picky/{extensions → internals/extensions}/object.rb +0 -0
  25. data/lib/picky/{extensions → internals/extensions}/symbol.rb +0 -0
  26. data/lib/picky/internals/frontend_adapters/rack.rb +154 -0
  27. data/lib/picky/internals/generators/base.rb +19 -0
  28. data/lib/picky/internals/generators/partial/default.rb +7 -0
  29. data/lib/picky/internals/generators/partial/none.rb +35 -0
  30. data/lib/picky/internals/generators/partial/strategy.rb +29 -0
  31. data/lib/picky/internals/generators/partial/substring.rb +122 -0
  32. data/lib/picky/internals/generators/partial_generator.rb +19 -0
  33. data/lib/picky/internals/generators/similarity/default.rb +9 -0
  34. data/lib/picky/internals/generators/similarity/double_levenshtone.rb +81 -0
  35. data/lib/picky/internals/generators/similarity/none.rb +35 -0
  36. data/lib/picky/internals/generators/similarity/strategy.rb +11 -0
  37. data/lib/picky/internals/generators/similarity_generator.rb +19 -0
  38. data/lib/picky/internals/generators/strategy.rb +18 -0
  39. data/lib/picky/internals/generators/weights/default.rb +9 -0
  40. data/lib/picky/internals/generators/weights/logarithmic.rb +43 -0
  41. data/lib/picky/internals/generators/weights/strategy.rb +11 -0
  42. data/lib/picky/internals/generators/weights_generator.rb +19 -0
  43. data/lib/picky/{helpers → internals/helpers}/measuring.rb +0 -0
  44. data/lib/picky/internals/index/backend.rb +113 -0
  45. data/lib/picky/internals/index/file/basic.rb +101 -0
  46. data/lib/picky/internals/index/file/json.rb +38 -0
  47. data/lib/picky/internals/index/file/marshal.rb +38 -0
  48. data/lib/picky/internals/index/file/text.rb +60 -0
  49. data/lib/picky/internals/index/files.rb +24 -0
  50. data/lib/picky/internals/index/redis/basic.rb +77 -0
  51. data/lib/picky/internals/index/redis/list_hash.rb +46 -0
  52. data/lib/picky/internals/index/redis/string_hash.rb +35 -0
  53. data/lib/picky/internals/index/redis.rb +44 -0
  54. data/lib/picky/internals/indexed/bundle/base.rb +72 -0
  55. data/lib/picky/internals/indexed/bundle/memory.rb +69 -0
  56. data/lib/picky/internals/indexed/bundle/redis.rb +70 -0
  57. data/lib/picky/internals/indexed/categories.rb +135 -0
  58. data/lib/picky/internals/indexed/category.rb +90 -0
  59. data/lib/picky/internals/indexed/index.rb +57 -0
  60. data/lib/picky/{indexed → internals/indexed}/wrappers/bundle/calculation.rb +0 -0
  61. data/lib/picky/{indexed → internals/indexed}/wrappers/bundle/location.rb +4 -2
  62. data/lib/picky/{indexed → internals/indexed}/wrappers/bundle/wrapper.rb +1 -1
  63. data/lib/picky/internals/indexed/wrappers/exact_first.rb +65 -0
  64. data/lib/picky/{indexers → internals/indexers}/no_source_specified_error.rb +0 -0
  65. data/lib/picky/{indexers → internals/indexers}/serial.rb +2 -2
  66. data/lib/picky/{indexers → internals/indexers}/solr.rb +0 -0
  67. data/lib/picky/internals/indexing/bundle/base.rb +219 -0
  68. data/lib/picky/internals/indexing/bundle/memory.rb +25 -0
  69. data/lib/picky/internals/indexing/bundle/redis.rb +28 -0
  70. data/lib/picky/internals/indexing/bundle/super_base.rb +65 -0
  71. data/lib/picky/internals/indexing/categories.rb +42 -0
  72. data/lib/picky/internals/indexing/category.rb +120 -0
  73. data/lib/picky/internals/indexing/index.rb +67 -0
  74. data/lib/picky/{performant.rb → internals/performant.rb} +0 -0
  75. data/lib/picky/internals/query/allocation.rb +88 -0
  76. data/lib/picky/internals/query/allocations.rb +137 -0
  77. data/lib/picky/internals/query/combination.rb +80 -0
  78. data/lib/picky/internals/query/combinations/base.rb +84 -0
  79. data/lib/picky/internals/query/combinations/memory.rb +58 -0
  80. data/lib/picky/internals/query/combinations/redis.rb +59 -0
  81. data/lib/picky/internals/query/indexes.rb +180 -0
  82. data/lib/picky/internals/query/qualifiers.rb +81 -0
  83. data/lib/picky/internals/query/token.rb +215 -0
  84. data/lib/picky/internals/query/tokens.rb +89 -0
  85. data/lib/picky/{query → internals/query}/weights.rb +0 -0
  86. data/lib/picky/internals/results/base.rb +106 -0
  87. data/lib/picky/internals/results/full.rb +17 -0
  88. data/lib/picky/internals/results/live.rb +17 -0
  89. data/lib/picky/{solr → internals/solr}/schema_generator.rb +0 -0
  90. data/lib/picky/internals/tokenizers/base.rb +166 -0
  91. data/lib/picky/internals/tokenizers/index.rb +63 -0
  92. data/lib/picky/internals/tokenizers/query.rb +79 -0
  93. data/lib/picky/loader.rb +148 -112
  94. data/lib/picky/query/base.rb +57 -26
  95. data/lib/picky/query/full.rb +1 -1
  96. data/lib/picky/query/live.rb +1 -1
  97. data/lib/picky/sources/db.rb +27 -6
  98. data/lib/tasks/index.rake +3 -3
  99. data/lib/tasks/try.rake +2 -2
  100. data/spec/lib/aliases_spec.rb +9 -0
  101. data/spec/lib/application_spec.rb +3 -3
  102. data/spec/lib/generators/aliases_spec.rb +1 -0
  103. data/spec/lib/{index_api_spec.rb → index/base_spec.rb} +7 -7
  104. data/spec/lib/index_bundle_spec.rb +71 -0
  105. data/spec/lib/indexed/indexes_spec.rb +61 -0
  106. data/spec/lib/indexing/indexes_spec.rb +94 -24
  107. data/spec/lib/{adapters → internals/adapters}/rack/base_spec.rb +2 -2
  108. data/spec/lib/{adapters → internals/adapters}/rack/live_parameters_spec.rb +2 -2
  109. data/spec/lib/{adapters → internals/adapters}/rack/query_spec.rb +2 -2
  110. data/spec/lib/{calculations → internals/calculations}/location_spec.rb +0 -0
  111. data/spec/lib/{cli_spec.rb → internals/cli_spec.rb} +4 -1
  112. data/spec/lib/{configuration → internals/configuration}/index_spec.rb +1 -1
  113. data/spec/lib/{cores_spec.rb → internals/cores_spec.rb} +0 -0
  114. data/spec/lib/{extensions → internals/extensions}/array_spec.rb +0 -0
  115. data/spec/lib/{extensions → internals/extensions}/hash_spec.rb +0 -0
  116. data/spec/lib/{extensions → internals/extensions}/module_spec.rb +0 -0
  117. data/spec/lib/{extensions → internals/extensions}/object_spec.rb +0 -0
  118. data/spec/lib/{extensions → internals/extensions}/symbol_spec.rb +0 -0
  119. data/spec/lib/{frontend_adapters → internals/frontend_adapters}/rack_spec.rb +11 -11
  120. data/spec/lib/{cacher → internals/generators}/cacher_strategy_spec.rb +2 -2
  121. data/spec/lib/internals/generators/partial/default_spec.rb +17 -0
  122. data/spec/lib/internals/generators/partial/none_spec.rb +17 -0
  123. data/spec/lib/{cacher → internals/generators}/partial/substring_spec.rb +26 -27
  124. data/spec/lib/{cacher → internals/generators}/partial_generator_spec.rb +5 -5
  125. data/spec/lib/{cacher → internals/generators}/similarity/double_levenshtone_spec.rb +4 -4
  126. data/spec/lib/{cacher → internals/generators}/similarity/none_spec.rb +2 -2
  127. data/spec/lib/{cacher → internals/generators}/similarity_generator_spec.rb +4 -4
  128. data/spec/lib/{cacher → internals/generators}/weights/logarithmic_spec.rb +2 -2
  129. data/spec/lib/internals/generators/weights_generator_spec.rb +21 -0
  130. data/spec/lib/{helpers → internals/helpers}/measuring_spec.rb +0 -0
  131. data/spec/lib/{index → internals/index}/file/basic_spec.rb +2 -2
  132. data/spec/lib/{index → internals/index}/file/json_spec.rb +2 -2
  133. data/spec/lib/{index → internals/index}/file/marshal_spec.rb +2 -2
  134. data/spec/lib/{index → internals/index}/file/text_spec.rb +2 -2
  135. data/spec/lib/{index → internals/index}/files_spec.rb +2 -2
  136. data/spec/lib/{indexed/bundle_spec.rb → internals/indexed/bundle/memory_spec.rb} +4 -5
  137. data/spec/lib/{indexed → internals/indexed}/categories_spec.rb +13 -13
  138. data/spec/lib/{indexed → internals/indexed}/category_spec.rb +59 -32
  139. data/spec/lib/{indexed → internals/indexed}/index_spec.rb +5 -5
  140. data/spec/lib/{indexed → internals/indexed}/wrappers/bundle/calculation_spec.rb +0 -0
  141. data/spec/lib/{indexed → internals/indexed}/wrappers/bundle/wrapper_spec.rb +0 -0
  142. data/spec/lib/{indexed → internals/indexed}/wrappers/exact_first_spec.rb +5 -5
  143. data/spec/lib/{indexers → internals/indexers}/serial_spec.rb +0 -0
  144. data/spec/lib/{indexing/bundle_partial_generation_speed_spec.rb → internals/indexing/bundle/memory_partial_generation_speed_spec.rb} +3 -3
  145. data/spec/lib/{indexing/bundle_spec.rb → internals/indexing/bundle/memory_spec.rb} +3 -3
  146. data/spec/lib/{index/bundle_spec.rb → internals/indexing/bundle/super_base_spec.rb} +9 -3
  147. data/spec/lib/{indexing → internals/indexing}/category_spec.rb +3 -3
  148. data/spec/lib/{indexing → internals/indexing}/index_spec.rb +3 -3
  149. data/spec/lib/internals/indexing/indexes_spec.rb +36 -0
  150. data/spec/lib/{interfaces → internals/interfaces}/live_parameters_spec.rb +0 -0
  151. data/spec/lib/internals/results/base_spec.rb +105 -0
  152. data/spec/lib/internals/results/full_spec.rb +78 -0
  153. data/spec/lib/internals/results/live_spec.rb +88 -0
  154. data/spec/lib/{solr → internals/solr}/schema_generator_spec.rb +0 -0
  155. data/spec/lib/{tokenizers → internals/tokenizers}/base_spec.rb +3 -3
  156. data/spec/lib/{tokenizers → internals/tokenizers}/index_spec.rb +9 -9
  157. data/spec/lib/{tokenizers → internals/tokenizers}/query_spec.rb +11 -11
  158. data/spec/lib/query/allocation_spec.rb +12 -12
  159. data/spec/lib/query/allocations_spec.rb +19 -19
  160. data/spec/lib/query/base_spec.rb +28 -4
  161. data/spec/lib/query/combination_spec.rb +8 -9
  162. data/spec/lib/query/combinations/base_spec.rb +116 -0
  163. data/spec/lib/query/{combinations_spec.rb → combinations/memory_spec.rb} +14 -14
  164. data/spec/lib/query/combinations/redis_spec.rb +132 -0
  165. data/spec/lib/query/full_spec.rb +2 -2
  166. data/spec/lib/query/indexes_spec.rb +81 -0
  167. data/spec/lib/query/live_spec.rb +3 -3
  168. data/spec/lib/query/qualifiers_spec.rb +6 -6
  169. data/spec/lib/query/token_spec.rb +38 -38
  170. data/spec/lib/query/tokens_spec.rb +35 -35
  171. data/spec/lib/sources/db_spec.rb +23 -18
  172. metadata +212 -181
  173. data/lib/picky/adapters/rack/base.rb +0 -23
  174. data/lib/picky/adapters/rack/live_parameters.rb +0 -33
  175. data/lib/picky/adapters/rack/query.rb +0 -59
  176. data/lib/picky/adapters/rack.rb +0 -28
  177. data/lib/picky/cacher/convenience.rb +0 -3
  178. data/lib/picky/cacher/generator.rb +0 -15
  179. data/lib/picky/cacher/partial/default.rb +0 -5
  180. data/lib/picky/cacher/partial/none.rb +0 -31
  181. data/lib/picky/cacher/partial/strategy.rb +0 -21
  182. data/lib/picky/cacher/partial/substring.rb +0 -118
  183. data/lib/picky/cacher/partial_generator.rb +0 -15
  184. data/lib/picky/cacher/similarity/default.rb +0 -7
  185. data/lib/picky/cacher/similarity/double_levenshtone.rb +0 -77
  186. data/lib/picky/cacher/similarity/none.rb +0 -31
  187. data/lib/picky/cacher/similarity/strategy.rb +0 -9
  188. data/lib/picky/cacher/similarity_generator.rb +0 -15
  189. data/lib/picky/cacher/strategy.rb +0 -12
  190. data/lib/picky/cacher/weights/default.rb +0 -7
  191. data/lib/picky/cacher/weights/logarithmic.rb +0 -39
  192. data/lib/picky/cacher/weights/strategy.rb +0 -9
  193. data/lib/picky/cacher/weights_generator.rb +0 -15
  194. data/lib/picky/frontend_adapters/rack.rb +0 -150
  195. data/lib/picky/index/bundle.rb +0 -54
  196. data/lib/picky/index/file/basic.rb +0 -97
  197. data/lib/picky/index/file/json.rb +0 -34
  198. data/lib/picky/index/file/marshal.rb +0 -34
  199. data/lib/picky/index/file/text.rb +0 -56
  200. data/lib/picky/index/files.rb +0 -118
  201. data/lib/picky/index_api.rb +0 -175
  202. data/lib/picky/indexed/bundle.rb +0 -54
  203. data/lib/picky/indexed/categories.rb +0 -131
  204. data/lib/picky/indexed/category.rb +0 -85
  205. data/lib/picky/indexed/index.rb +0 -39
  206. data/lib/picky/indexed/wrappers/exact_first.rb +0 -61
  207. data/lib/picky/indexing/bundle.rb +0 -213
  208. data/lib/picky/indexing/categories.rb +0 -38
  209. data/lib/picky/indexing/category.rb +0 -117
  210. data/lib/picky/indexing/index.rb +0 -55
  211. data/lib/picky/query/allocation.rb +0 -82
  212. data/lib/picky/query/allocations.rb +0 -130
  213. data/lib/picky/query/combination.rb +0 -74
  214. data/lib/picky/query/combinations.rb +0 -105
  215. data/lib/picky/query/qualifiers.rb +0 -77
  216. data/lib/picky/query/token.rb +0 -202
  217. data/lib/picky/query/tokens.rb +0 -86
  218. data/lib/picky/query/weigher.rb +0 -165
  219. data/lib/picky/results/base.rb +0 -102
  220. data/lib/picky/results/full.rb +0 -13
  221. data/lib/picky/results/live.rb +0 -13
  222. data/lib/picky/tokenizers/base.rb +0 -161
  223. data/lib/picky/tokenizers/index.rb +0 -58
  224. data/lib/picky/tokenizers/query.rb +0 -74
  225. data/spec/lib/cacher/partial/default_spec.rb +0 -15
  226. data/spec/lib/cacher/partial/none_spec.rb +0 -17
  227. data/spec/lib/cacher/weights_generator_spec.rb +0 -21
  228. data/spec/lib/results/base_spec.rb +0 -257
  229. data/spec/lib/results/live_spec.rb +0 -15
@@ -1,6 +1,4 @@
1
1
  # This provides a nice accessor for users
2
2
  # who want to use the index API.
3
3
  #
4
- # TODO Rename to API::Indexes?
5
- #
6
- Indexes = IndexesAPI.new
4
+ Indexes = IndexBundle.new
@@ -13,21 +13,23 @@
13
13
  # will generate an example <tt>project_name/app/application.rb</tt> file for you
14
14
  # with some example code inside.
15
15
  #
16
- # == index(name, source)
16
+ # == Index::Memory.new(name, source)
17
17
  #
18
- # Next, define where your data comes from. You use the <tt>index</tt> method for that:
19
- # my_index = index :some_index_name, some_source
18
+ # Next, define where your data comes from. You use the <tt>Index::Memory.new</tt> method for that:
19
+ # my_index = Index::Memory.new :some_index_name, some_source
20
20
  # You give the index a name (or identifier), and a source (see Sources), where its data comes from. Let's do that:
21
21
  # class MyGreatSearch < Application
22
22
  #
23
- # books = index :books, Sources::CSV.new(:title, :author, :isbn, file:'app/library.csv')
23
+ # books = Index::Memory.new :books, Sources::CSV.new(:title, :author, :isbn, file:'app/library.csv')
24
24
  #
25
25
  # end
26
26
  # Now we have an index <tt>books</tt>.
27
27
  #
28
28
  # That on itself won't do much good.
29
29
  #
30
- # == index.define_category(identifier, options = {})
30
+ # Note that a Redis index is also available: Index::Redis.new.
31
+ #
32
+ # == index_instance.define_category(identifier, options = {})
31
33
  #
32
34
  # Picky needs us to define categories on the data.
33
35
  #
@@ -37,7 +39,7 @@
37
39
  # Let's go ahead and define a category:
38
40
  # class MyGreatSearch < Application
39
41
  #
40
- # books = index :books, Sources::CSV.new(:title, :author, :isbn, file:'app/library.csv')
42
+ # books = Index::Memory.new :books, Sources::CSV.new(:title, :author, :isbn, file:'app/library.csv')
41
43
  # books.define_category :title
42
44
  #
43
45
  # end
@@ -67,9 +69,7 @@
67
69
  # books = index :books, Sources::CSV.new(:title, :author, :isbn, file:'app/library.csv')
68
70
  # books.define_category :title
69
71
  #
70
- # full_books_query = Query::Full.new books
71
- #
72
- # route %r{^/books/full$} => full_books_query
72
+ # route %r{^/books/full$} => Query::Full.new(books)
73
73
  #
74
74
  # end
75
75
  # That's it!
@@ -128,7 +128,7 @@
128
128
  # substitutes_characters_with: CharacterSubstituters::WestEuropean.new,
129
129
  # maximum_tokens: 4
130
130
  #
131
- # books = index :books, Sources::CSV.new(:title, :author, :isbn, file:'app/library.csv')
131
+ # books = Index::Memory.new :books, Sources::CSV.new(:title, :author, :isbn, file:'app/library.csv')
132
132
  # books.define_category :title,
133
133
  # qualifiers: [:t, :title, :titre],
134
134
  # partial: Partial::Substring.new(:from => 1),
@@ -139,11 +139,8 @@
139
139
  #
140
140
  # query_options = { :weights => { [:title, :author] => +3, [:author, :title] => -1 } }
141
141
  #
142
- # full_books_query = Query::Full.new books, query_options
143
- # live_books_query = Query::Full.new books, query_options
144
- #
145
- # route %r{^/books/full$} => full_books_query
146
- # route %r{^/books/live$} => live_books_query
142
+ # route %r{^/books/full$} => Query::Full.new(books, query_options)
143
+ # route %r{^/books/live$} => Query::Live.new(books, query_options)
147
144
  #
148
145
  # end
149
146
  # That's actually already a full-blown Picky App!
@@ -159,14 +156,14 @@ class Application
159
156
  # is used for indexing by default.
160
157
  #
161
158
  def default_indexing options = {}
162
- Tokenizers::Index.default = Tokenizers::Index.new(options)
159
+ Internals::Tokenizers::Index.default = Internals::Tokenizers::Index.new(options)
163
160
  end
164
161
 
165
162
  # Returns a configured tokenizer that
166
163
  # is used for querying by default.
167
164
  #
168
165
  def default_querying options = {}
169
- Tokenizers::Query.default = Tokenizers::Query.new(options)
166
+ Internals::Tokenizers::Query.default = Internals::Tokenizers::Query.new(options)
170
167
  end
171
168
 
172
169
  # Create a new index for indexing and for querying.
@@ -181,8 +178,10 @@ class Application
181
178
  # Options:
182
179
  # * result_identifier: Use if you'd like a different identifier/name in the results JSON than the name of the index.
183
180
  #
181
+ # TODO Obsolete. Phase out.
182
+ #
184
183
  def index name, source, options = {}
185
- IndexAPI.new name, source, options
184
+ Index::Memory.new name, source, options
186
185
  end
187
186
 
188
187
  # Routes.
@@ -201,7 +200,7 @@ class Application
201
200
  rack_adapter.call env
202
201
  end
203
202
  def rack_adapter # :nodoc:
204
- @rack_adapter ||= FrontendAdapters::Rack.new
203
+ @rack_adapter ||= Internals::FrontendAdapters::Rack.new
205
204
  end
206
205
 
207
206
  # Finalize the subclass as soon as it
data/lib/picky/cores.rb CHANGED
@@ -83,7 +83,7 @@ class Cores # :nodoc:all
83
83
  # os_name => lambda_which_returns_a_number_of_cores
84
84
  #
85
85
  @@number_of_cores = {
86
- 'darwin' => lambda { `system_profiler SPHardwareDataType | grep 'Total Number Of Cores'`.gsub(/[^\d]/, '') },
86
+ 'darwin' => lambda { `system_profiler SPHardwareDataType | grep -i 'Total Number Of Cores'`.gsub(/[^\d]/, '') },
87
87
  'linux' => lambda { `grep -ci ^processor /proc/cpuinfo` }
88
88
  }
89
89
  def self.os_to_core_mapping
@@ -0,0 +1,3 @@
1
+ Partial = Internals::Generators::Partial
2
+ Similarity = Internals::Generators::Similarity
3
+ Weights = Internals::Generators::Weights
@@ -0,0 +1,179 @@
1
+ module Index
2
+
3
+ # This class defines the indexing and index API that is exposed to the user
4
+ # as the #index method inside the Application class.
5
+ #
6
+ # It provides a single front for both indexing and index options. We suggest to always use the index API.
7
+ #
8
+ # Note: An Index holds both an *Indexed*::*Index* and an *Indexing*::*Type*.
9
+ #
10
+ class Base
11
+
12
+ attr_reader :name, :indexing, :indexed
13
+
14
+ # Create a new index with a given source.
15
+ #
16
+ # === Parameters
17
+ # * name: A name that will be used for the index directory and in the Picky front end.
18
+ # * source: Where the data comes from, e.g. Sources::CSV.new(...)
19
+ #
20
+ # === Options
21
+ # * result_identifier: Use if you'd like a different identifier/name in the results than the name of the index.
22
+ # * after_indexing: As of this writing only used in the db source. Executes the given after_indexing as SQL after the indexing process.
23
+ #
24
+ def initialize name, source, options = {}
25
+ @name = name
26
+ @indexing = Internals::Indexing::Index.new name, source, options
27
+ @indexed = Internals::Indexed::Index.new name, options
28
+
29
+ # Centralized registry.
30
+ #
31
+ Indexes.register self
32
+ end
33
+
34
+ # Defines a searchable category on the index.
35
+ #
36
+ # === Parameters
37
+ # * category_name: This identifier is used in the front end, but also to categorize query text. For example, “title:hobbit” will narrow the hobbit query on categories with the identifier :title.
38
+ #
39
+ # === Options
40
+ # * partial: Partial::None.new or Partial::Substring.new(from: starting_char, to: ending_char). Default is Partial::Substring.new(from: -3, to: -1).
41
+ # * similarity: Similarity::None.new or Similarity::Phonetic.new(similar_words_searched). Default is Similarity::None.new.
42
+ # * qualifiers: An array of qualifiers with which you can define which category you’d like to search, for example “title:hobbit” will search for hobbit in just title categories. Example: qualifiers: [:t, :titre, :title] (use it for example with multiple languages). Default is the name of the category.
43
+ # * qualifier: Convenience options if you just need a single qualifier, see above. Example: qualifiers => :title. Default is the name of the category.
44
+ # * source: Use a different source than the index uses. If you think you need that, there might be a better solution to your problem. Please post to the mailing list first with your application.rb :)
45
+ # * from: Take the data from the data category with this name. Example: You have a source Sources::CSV.new(:title, file:'some_file.csv') but you want the category to be called differently. The you use from: define_category(:similar_title, :from => :title).
46
+ #
47
+ def define_category category_name, options = {}
48
+ category_name = category_name.to_sym
49
+
50
+ indexing_category = indexing.define_category category_name, options
51
+ indexed_category = indexed.define_category category_name, options
52
+
53
+ yield indexing_category, indexed_category if block_given?
54
+
55
+ self
56
+ end
57
+ alias category define_category
58
+
59
+ # HIGHLY EXPERIMENTAL Try if you feel "beta" ;)
60
+ #
61
+ # Make this category range searchable with a fixed range. If you need other ranges, define another category with a different range value.
62
+ #
63
+ # Example:
64
+ # You have data values inside 1..100, and you want to have Picky return
65
+ # not only the results for 47 if you search for 47, but also results for
66
+ # 45, 46, or 47.2, 48.9, in a range of 2 around 47, so (45..49).
67
+ #
68
+ # Then you use:
69
+ # my_index.define_ranged_category :values_inside_1_100, 2
70
+ #
71
+ # Optionally, you give it a precision value to reduce the error margin
72
+ # around 47 (Picky is a bit liberal).
73
+ # my_index.define_ranged_category :values_inside_1_100, 2, precision: 5
74
+ #
75
+ # This will force Picky to maximally be wrong 5% of the given range value
76
+ # (5% of 2 = 0.1) instead of the default 20% (20% of 2 = 0.4).
77
+ #
78
+ # We suggest not to use much more than 5 as a higher precision is more performance intensive for less and less precision gain.
79
+ #
80
+ # == Protip 1
81
+ #
82
+ # Create two ranged categories to make an area search:
83
+ # index.define_ranged_category :x, 1
84
+ # index.define_ranged_category :y, 1
85
+ #
86
+ # Search for it using for example:
87
+ # x:133, y:120
88
+ #
89
+ # This will search this square area (* = 133, 120: The "search" point entered):
90
+ #
91
+ # 132 134
92
+ # | |
93
+ # --|---------|-- 121
94
+ # | |
95
+ # | * |
96
+ # | |
97
+ # --|---------|-- 119
98
+ # | |
99
+ #
100
+ # Note: The area does not need to be square, but can be rectangular.
101
+ #
102
+ # == Protip 2
103
+ #
104
+ # Create three ranged categories to make a volume search.
105
+ #
106
+ # Or go crazy and use 4 ranged categories for a space/time search! ;)
107
+ #
108
+ # === Parameters
109
+ # * category_name: The category_name as used in #define_category.
110
+ # * range: The range (in the units of your data values) around the query point where we search for results.
111
+ #
112
+ # -----|<- range ->*------------|-----
113
+ #
114
+ # === Options
115
+ # * precision: Default is 1 (20% error margin, very fast), up to 5 (5% error margin, slower) makes sense.
116
+ # * ... all options of #define_category.
117
+ #
118
+ def define_ranged_category category_name, range, options = {}
119
+ precision = options[:precision]
120
+
121
+ options = { partial: Partial::None.new }.merge options
122
+
123
+ define_category category_name, options do |indexing, indexed|
124
+ indexing.source = Sources::Wrappers::Location.new indexing, grid: range, precision: precision
125
+ indexing.tokenizer = Internals::Tokenizers::Index.new
126
+
127
+ exact_bundle = Indexed::Wrappers::Bundle::Location.new indexed.exact, grid: range, precision: precision
128
+ indexed.exact = exact_bundle
129
+ indexed.partial = exact_bundle # A partial token also uses the exact index.
130
+ end
131
+ end
132
+ alias ranged_category define_ranged_category
133
+
134
+ # HIGHLY EXPERIMENTAL Not correctly working yet. Try it if you feel "beta".
135
+ #
136
+ # Also a range search see #define_ranged_category, but on the earth's surface.
137
+ #
138
+ # Parameters:
139
+ # * name: The name as used in #define_category.
140
+ # * radius: The distance (in km) around the query point which we search for results.
141
+ #
142
+ # Note: Picky uses a square, not a circle. We hope that's ok for most usages.
143
+ #
144
+ # -----------------------------
145
+ # | |
146
+ # | |
147
+ # | |
148
+ # | |
149
+ # | |
150
+ # | *<- radius ->|
151
+ # | |
152
+ # | |
153
+ # | |
154
+ # | |
155
+ # | |
156
+ # -----------------------------
157
+ #
158
+ # Options
159
+ # * precision: Default 1 (20% error margin, very fast), up to 5 (5% error margin, slower) makes sense.
160
+ # * from: The data category to take the data for this category from.
161
+ #
162
+ # TODO Redo. Will have to write a wrapper that combines two categories that are indexed simultaneously.
163
+ #
164
+ def define_map_location name, radius, options = {} # :nodoc:
165
+ # The radius is given as if all the locations were on the equator.
166
+ #
167
+ # TODO Need to recalculate since not many locations are on the equator ;) This is just a prototype.
168
+ #
169
+ # This calculates km -> longitude (degrees).
170
+ #
171
+ # A degree on the equator is equal to ~111,319.9 meters.
172
+ # So a km on the equator is equal to 0.00898312 degrees.
173
+ #
174
+ define_ranged_category name, radius * 0.00898312, options
175
+ end
176
+ alias map_location define_map_location
177
+ end
178
+
179
+ end
@@ -0,0 +1,28 @@
1
+ module Index
2
+
3
+ # An index that is persisted in files, loaded at startup and kept in memory at runtime.
4
+ #
5
+ class Memory < Base
6
+
7
+ # Create a new memory index for indexing and for querying.
8
+ #
9
+ # Parameters:
10
+ # * name: The identifier of the index. Used:
11
+ # - to identify an index (e.g. by you in Rake tasks: Indexes[:the_identifier]).
12
+ # - in the frontend to describe which index a result came from.
13
+ # - index directory naming (index/development/the_identifier/<lots of indexes>)
14
+ # * source: The source the data comes from. See Sources::Base.
15
+ #
16
+ # Options:
17
+ # * result_identifier: Use if you'd like a different identifier/name in the results JSON than the name of the index.
18
+ #
19
+ def initialize name, source, options = {}
20
+ options[:indexing_bundle_class] ||= Internals::Indexing::Bundle::Memory
21
+ options[:indexed_bundle_class] ||= Internals::Indexed::Bundle::Memory
22
+
23
+ super name, source, options
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,28 @@
1
+ module Index
2
+
3
+ # An index that is persisted in Redis.
4
+ #
5
+ class Redis < Base
6
+
7
+ # Create a new Redis index for indexing and for querying.
8
+ #
9
+ # Parameters:
10
+ # * name: The identifier of the index. Used:
11
+ # - to identify an index (e.g. by you in Rake tasks: Indexes[:the_identifier]).
12
+ # - in the frontend to describe which index a result came from.
13
+ # - index directory naming (index/development/the_identifier/<lots of indexes>)
14
+ # * source: The source the data comes from. See Sources::Base.
15
+ #
16
+ # Options:
17
+ # * result_identifier: Use if you'd like a different identifier/name in the results JSON than the name of the index.
18
+ #
19
+ def initialize name, source, options = {}
20
+ options[:indexing_bundle_class] ||= Internals::Indexing::Bundle::Redis
21
+ options[:indexed_bundle_class] ||= Internals::Indexed::Bundle::Redis
22
+
23
+ super name, source, options
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -1,41 +1,41 @@
1
1
  # Comfortable API convenience class, splits methods to indexes.
2
2
  #
3
- class IndexesAPI # :nodoc:all
4
-
5
- attr_reader :indexes, :index_mapping
6
-
3
+ class IndexBundle # :nodoc:all
4
+
5
+ attr_reader :indexes, :index_mapping, :indexing, :indexed
6
+
7
7
  delegate :reload,
8
8
  :load_from_cache,
9
- :to => :@indexed
10
-
9
+ :to => :indexed
10
+
11
11
  delegate :check_caches,
12
12
  :find,
13
13
  :generate_cache_only,
14
14
  :generate_index_only,
15
15
  :index,
16
16
  :index_for_tests,
17
- :to => :@indexing
18
-
17
+ :to => :indexing
18
+
19
19
  def initialize
20
20
  @indexes = []
21
21
  @index_mapping = {}
22
-
22
+
23
23
  @indexed = Indexed::Indexes.new
24
24
  @indexing = Indexing::Indexes.new
25
25
  end
26
-
26
+
27
27
  def register index
28
28
  self.indexes << index
29
29
  self.index_mapping[index.name] = index
30
-
31
- @indexing.register index.indexing
32
- @indexed.register index.indexed
33
- end
34
30
 
31
+ indexing.register index.indexing
32
+ indexed.register index.indexed
33
+ end
34
+
35
35
  def [] name
36
36
  name = name.to_sym
37
-
37
+
38
38
  self.index_mapping[name]
39
39
  end
40
-
40
+
41
41
  end
@@ -1,5 +1,7 @@
1
1
  module Indexed
2
2
 
3
+ # Registers the indexes held at runtime, for queries.
4
+ #
3
5
  class Indexes
4
6
 
5
7
  attr_reader :indexes, :index_mapping
@@ -11,29 +13,31 @@ module Indexed
11
13
  clear
12
14
  end
13
15
 
14
- # TODO Spec.
16
+ # Clears the indexes and the mapping.
15
17
  #
16
18
  def clear
17
19
  @indexes = []
18
20
  @index_mapping = {}
19
21
  end
20
22
 
21
- # TODO Spec.
23
+ # Reloads all indexes, one after another,
24
+ # in the order they were added.
22
25
  #
23
26
  def reload
24
27
  load_from_cache
25
28
  end
26
29
 
27
- # TODO Spec
30
+ # Registers an index with the indexes.
28
31
  #
29
32
  def register index
30
33
  self.indexes << index
31
34
  self.index_mapping[index.name] = index
32
35
  end
33
- def [] name
34
- name = name.to_sym
35
-
36
- index_mapping[name]
36
+
37
+ # Extracts an index, given its identifier.
38
+ #
39
+ def [] identifier
40
+ index_mapping[identifier.to_sym]
37
41
  end
38
42
 
39
43
  end
@@ -1,5 +1,7 @@
1
1
  module Indexing
2
2
 
3
+ # Registers the indexes held at index time, for indexing.
4
+ #
3
5
  class Indexes
4
6
 
5
7
  attr_reader :indexes
@@ -17,13 +19,13 @@ module Indexing
17
19
  clear
18
20
  end
19
21
 
20
- # TODO Doc.
22
+ # Clears the array of indexes.
21
23
  #
22
24
  def clear
23
25
  @indexes = []
24
26
  end
25
27
 
26
- # TODO Spec. Superclass?
28
+ # Registers an index with the indexes.
27
29
  #
28
30
  def register index
29
31
  self.indexes << index
@@ -52,7 +54,7 @@ module Indexing
52
54
  timed_exclaim "INDEXING FINISHED."
53
55
  end
54
56
 
55
- # For testing.
57
+ # For integration testing – indexes for the tests without forking and shouting ;)
56
58
  #
57
59
  def index_for_tests
58
60
  take_snapshot
@@ -63,25 +65,29 @@ module Indexing
63
65
  end
64
66
  end
65
67
 
66
- # TODO Spec
68
+ # Generate only the index for the given index:category pair.
67
69
  #
68
- def generate_index_only index_name, category_name
70
+ def generate_index_only index_name, category_name = nil
69
71
  found = find index_name, category_name
70
72
  found.index if found
71
73
  end
72
- def generate_cache_only index_name, category_name
74
+ # Generate only the cache for the given index:category pair.
75
+ #
76
+ def generate_cache_only index_name, category_name = nil
73
77
  found = find index_name, category_name
74
78
  found.generate_caches if found
75
79
  end
76
80
 
77
- # TODO Spec
81
+ # Find a given index:category pair.
78
82
  #
79
83
  def find index_name, category_name
80
- index_name = index_name.to_sym
84
+ index_name = index_name.to_sym
81
85
 
82
86
  indexes.each do |index|
83
87
  next unless index.name == index_name
84
88
 
89
+ return index unless category_name
90
+
85
91
  found = index.categories.find category_name
86
92
  return found if found
87
93
  end
@@ -0,0 +1,27 @@
1
+ module Internals
2
+
3
+ module Adapters
4
+ # Adapter that is plugged into a Rack outlet.
5
+ #
6
+ module Rack
7
+
8
+ # Subclasses of this class should respond to
9
+ # * to_app(options)
10
+ #
11
+ class Base
12
+
13
+ # Puts together an appropriately structured Rack response.
14
+ #
15
+ # Note: Bytesize is needed to have special characters not trip up Rack.
16
+ #
17
+ def respond_with response, content_type = 'application/json'
18
+ [200, { 'Content-Type' => content_type, 'Content-Length' => response.bytesize.to_s }, [response]]
19
+ end
20
+
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,37 @@
1
+ module Internals
2
+
3
+ module Adapters
4
+
5
+ #
6
+ #
7
+ module Rack
8
+
9
+ class LiveParameters < Base
10
+
11
+ def initialize live_parameters
12
+ @live_parameters = live_parameters
13
+ end
14
+
15
+ #
16
+ #
17
+ def to_app options = {}
18
+ # For capturing by the lambda block.
19
+ #
20
+ live_parameters = @live_parameters
21
+
22
+ lambda do |env|
23
+ params = ::Rack::Request.new(env).params
24
+
25
+ results = live_parameters.parameters params
26
+
27
+ respond_with results.to_json
28
+ end
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,63 @@
1
+ module Internals
2
+
3
+ module Adapters
4
+ # This is an adapter that is plugged into a Rack outlet.
5
+ #
6
+ # It looks at what is given to it and generate an appropriate
7
+ # adapter for it.
8
+ #
9
+ # For example, if you give it a query, it will extract the query param etc.
10
+ # and call search_with_text on it if it is called by Rack.
11
+ #
12
+ module Rack
13
+
14
+ class Query < Base
15
+
16
+ @@defaults = {
17
+ query_key: 'query'.freeze,
18
+ offset_key: 'offset'.freeze,
19
+ content_type: 'application/json'.freeze
20
+ }
21
+
22
+ def initialize query
23
+ @query = query
24
+ @defaults = @@defaults.dup
25
+ end
26
+
27
+ def to_app options = {}
28
+ # For capturing in the lambda.
29
+ #
30
+ query = @query
31
+ query_key = options[:query_key] || @defaults[:query_key]
32
+ content_type = options[:content_type] || @defaults[:content_type]
33
+
34
+ lambda do |env|
35
+ params = ::Rack::Request.new(env).params
36
+
37
+ results = query.search_with_text *extracted(params)
38
+
39
+ PickyLog.log results.to_log(params[query_key])
40
+
41
+ respond_with results.to_response, content_type
42
+ end
43
+ end
44
+
45
+ # Helper method to extract the params
46
+ #
47
+ UTF8_STRING = 'UTF-8'.freeze
48
+ def extracted params
49
+ [
50
+ # query is encoded in ASCII
51
+ #
52
+ params[@defaults[:query_key]] && params[@defaults[:query_key]].force_encoding(UTF8_STRING),
53
+ params[@defaults[:offset_key]] && params[@defaults[:offset_key]].to_i || 0
54
+ ]
55
+ end
56
+
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+
63
+ end