picky 2.7.0 → 3.0.0.pre1

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 (213) hide show
  1. data/lib/picky/adapters/rack/base.rb +20 -16
  2. data/lib/picky/adapters/rack/live_parameters.rb +28 -24
  3. data/lib/picky/adapters/rack/search.rb +67 -0
  4. data/lib/picky/adapters/rack.rb +27 -23
  5. data/lib/picky/application.rb +246 -236
  6. data/lib/picky/backend/base.rb +115 -119
  7. data/lib/picky/backend/file/basic.rb +102 -98
  8. data/lib/picky/backend/file/json.rb +27 -23
  9. data/lib/picky/backend/file/marshal.rb +32 -28
  10. data/lib/picky/backend/file/text.rb +45 -41
  11. data/lib/picky/backend/files.rb +19 -15
  12. data/lib/picky/backend/redis/basic.rb +76 -72
  13. data/lib/picky/backend/redis/list_hash.rb +40 -36
  14. data/lib/picky/backend/redis/string_hash.rb +30 -26
  15. data/lib/picky/backend/redis.rb +32 -28
  16. data/lib/picky/bundle.rb +82 -57
  17. data/lib/{bundling.rb → picky/bundling.rb} +0 -0
  18. data/lib/picky/calculations/location.rb +51 -47
  19. data/lib/picky/categories.rb +60 -56
  20. data/lib/picky/categories_indexed.rb +73 -82
  21. data/lib/picky/categories_indexing.rb +12 -8
  22. data/lib/picky/category.rb +109 -120
  23. data/lib/picky/category_indexed.rb +39 -41
  24. data/lib/picky/category_indexing.rb +123 -125
  25. data/lib/picky/character_substituters/west_european.rb +32 -26
  26. data/lib/{constants.rb → picky/constants.rb} +0 -0
  27. data/lib/picky/cores.rb +96 -92
  28. data/lib/{deployment.rb → picky/deployment.rb} +0 -0
  29. data/lib/picky/frontend_adapters/rack.rb +133 -118
  30. data/lib/picky/generators/aliases.rb +5 -3
  31. data/lib/picky/generators/base.rb +11 -7
  32. data/lib/picky/generators/partial/default.rb +7 -3
  33. data/lib/picky/generators/partial/none.rb +24 -20
  34. data/lib/picky/generators/partial/strategy.rb +20 -16
  35. data/lib/picky/generators/partial/substring.rb +94 -90
  36. data/lib/picky/generators/partial_generator.rb +11 -7
  37. data/lib/picky/generators/similarity/default.rb +9 -5
  38. data/lib/picky/generators/similarity/double_metaphone.rb +20 -16
  39. data/lib/picky/generators/similarity/metaphone.rb +20 -16
  40. data/lib/picky/generators/similarity/none.rb +23 -19
  41. data/lib/picky/generators/similarity/phonetic.rb +49 -45
  42. data/lib/picky/generators/similarity/soundex.rb +20 -16
  43. data/lib/picky/generators/similarity/strategy.rb +10 -6
  44. data/lib/picky/generators/similarity_generator.rb +11 -7
  45. data/lib/picky/generators/strategy.rb +14 -10
  46. data/lib/picky/generators/weights/default.rb +9 -5
  47. data/lib/picky/generators/weights/logarithmic.rb +30 -26
  48. data/lib/picky/generators/weights/strategy.rb +10 -6
  49. data/lib/picky/generators/weights_generator.rb +11 -7
  50. data/lib/picky/helpers/measuring.rb +20 -16
  51. data/lib/picky/indexed/bundle/base.rb +39 -37
  52. data/lib/picky/indexed/bundle/memory.rb +68 -64
  53. data/lib/picky/indexed/bundle/redis.rb +73 -69
  54. data/lib/picky/indexed/wrappers/bundle/calculation.rb +26 -22
  55. data/lib/picky/indexed/wrappers/bundle/location.rb +30 -26
  56. data/lib/picky/indexed/wrappers/bundle/wrapper.rb +36 -32
  57. data/lib/picky/indexed/wrappers/category/location.rb +17 -13
  58. data/lib/picky/indexed/wrappers/exact_first.rb +46 -42
  59. data/lib/picky/indexers/base.rb +26 -22
  60. data/lib/picky/indexers/parallel.rb +62 -58
  61. data/lib/picky/indexers/serial.rb +41 -37
  62. data/lib/picky/indexes/index.rb +400 -0
  63. data/lib/picky/indexes/index_indexed.rb +24 -0
  64. data/lib/picky/indexes/index_indexing.rb +138 -0
  65. data/lib/picky/indexes/memory.rb +20 -0
  66. data/lib/picky/indexes/redis.rb +20 -0
  67. data/lib/picky/indexes.rb +68 -61
  68. data/lib/picky/indexes_indexed.rb +16 -12
  69. data/lib/picky/indexes_indexing.rb +41 -37
  70. data/lib/picky/indexing/bundle/base.rb +216 -205
  71. data/lib/picky/indexing/bundle/memory.rb +16 -11
  72. data/lib/picky/indexing/bundle/redis.rb +14 -12
  73. data/lib/picky/indexing/wrappers/category/location.rb +17 -13
  74. data/lib/picky/interfaces/live_parameters.rb +159 -154
  75. data/lib/picky/loader.rb +267 -304
  76. data/lib/picky/loggers/search.rb +20 -13
  77. data/lib/picky/no_source_specified_exception.rb +7 -3
  78. data/lib/picky/performant.rb +6 -2
  79. data/lib/picky/query/allocation.rb +71 -67
  80. data/lib/picky/query/allocations.rb +99 -94
  81. data/lib/picky/query/combination.rb +70 -66
  82. data/lib/picky/query/combinations/base.rb +56 -52
  83. data/lib/picky/query/combinations/memory.rb +36 -32
  84. data/lib/picky/query/combinations/redis.rb +66 -62
  85. data/lib/picky/query/indexes.rb +175 -160
  86. data/lib/picky/query/qualifier_category_mapper.rb +43 -0
  87. data/lib/picky/query/token.rb +165 -172
  88. data/lib/picky/query/tokens.rb +86 -82
  89. data/lib/picky/query/weights.rb +44 -48
  90. data/lib/picky/query.rb +5 -1
  91. data/lib/picky/rack/harakiri.rb +51 -47
  92. data/lib/picky/results.rb +81 -77
  93. data/lib/picky/search.rb +169 -158
  94. data/lib/picky/sinatra.rb +34 -0
  95. data/lib/picky/sources/base.rb +73 -70
  96. data/lib/picky/sources/couch.rb +61 -57
  97. data/lib/picky/sources/csv.rb +68 -64
  98. data/lib/picky/sources/db.rb +139 -135
  99. data/lib/picky/sources/delicious.rb +52 -48
  100. data/lib/picky/sources/mongo.rb +68 -63
  101. data/lib/picky/sources/wrappers/base.rb +20 -16
  102. data/lib/picky/sources/wrappers/location.rb +37 -33
  103. data/lib/picky/statistics.rb +46 -43
  104. data/lib/picky/tasks.rb +3 -0
  105. data/lib/picky/tokenizers/base.rb +192 -187
  106. data/lib/picky/tokenizers/index.rb +25 -21
  107. data/lib/picky/tokenizers/location.rb +33 -29
  108. data/lib/picky/tokenizers/query.rb +49 -43
  109. data/lib/picky.rb +21 -13
  110. data/lib/tasks/application.rake +1 -1
  111. data/lib/tasks/index.rake +3 -3
  112. data/lib/tasks/routes.rake +1 -1
  113. data/lib/tasks/server.rake +1 -1
  114. data/spec/lib/adapters/rack/base_spec.rb +1 -1
  115. data/spec/lib/adapters/rack/live_parameters_spec.rb +1 -1
  116. data/spec/lib/adapters/rack/query_spec.rb +1 -1
  117. data/spec/lib/application_spec.rb +39 -32
  118. data/spec/lib/backend/file/basic_spec.rb +2 -2
  119. data/spec/lib/backend/file/json_spec.rb +2 -2
  120. data/spec/lib/backend/file/marshal_spec.rb +2 -2
  121. data/spec/lib/backend/file/text_spec.rb +1 -1
  122. data/spec/lib/backend/files_spec.rb +14 -24
  123. data/spec/lib/backend/redis/basic_spec.rb +2 -2
  124. data/spec/lib/backend/redis/list_hash_spec.rb +3 -3
  125. data/spec/lib/backend/redis/string_hash_spec.rb +3 -3
  126. data/spec/lib/backend/redis_spec.rb +20 -13
  127. data/spec/lib/calculations/location_spec.rb +1 -1
  128. data/spec/lib/categories_indexed_spec.rb +16 -34
  129. data/spec/lib/category_indexed_spec.rb +9 -27
  130. data/spec/lib/category_indexing_spec.rb +2 -3
  131. data/spec/lib/category_spec.rb +10 -10
  132. data/spec/lib/character_substituters/west_european_spec.rb +6 -5
  133. data/spec/lib/cores_spec.rb +17 -17
  134. data/spec/lib/extensions/symbol_spec.rb +15 -1
  135. data/spec/lib/frontend_adapters/rack_spec.rb +20 -20
  136. data/spec/lib/generators/aliases_spec.rb +3 -3
  137. data/spec/lib/generators/cacher_strategy_spec.rb +1 -1
  138. data/spec/lib/generators/partial/default_spec.rb +3 -3
  139. data/spec/lib/generators/partial/none_spec.rb +2 -2
  140. data/spec/lib/generators/partial/substring_spec.rb +1 -1
  141. data/spec/lib/generators/partial_generator_spec.rb +3 -3
  142. data/spec/lib/generators/similarity/double_metaphone_spec.rb +1 -1
  143. data/spec/lib/generators/similarity/metaphone_spec.rb +1 -1
  144. data/spec/lib/generators/similarity/none_spec.rb +1 -1
  145. data/spec/lib/generators/similarity/phonetic_spec.rb +1 -1
  146. data/spec/lib/generators/similarity/soundex_spec.rb +1 -1
  147. data/spec/lib/generators/similarity_generator_spec.rb +2 -2
  148. data/spec/lib/generators/weights/logarithmic_spec.rb +1 -1
  149. data/spec/lib/generators/weights_generator_spec.rb +1 -1
  150. data/spec/lib/helpers/measuring_spec.rb +2 -2
  151. data/spec/lib/indexed/bundle/memory_spec.rb +6 -6
  152. data/spec/lib/indexed/bundle/redis_spec.rb +4 -4
  153. data/spec/lib/indexed/wrappers/bundle/calculation_spec.rb +2 -3
  154. data/spec/lib/indexed/wrappers/bundle/wrapper_spec.rb +2 -2
  155. data/spec/lib/indexed/wrappers/exact_first_spec.rb +5 -5
  156. data/spec/lib/indexers/base_spec.rb +1 -1
  157. data/spec/lib/indexers/parallel_spec.rb +1 -1
  158. data/spec/lib/indexers/serial_spec.rb +1 -1
  159. data/spec/lib/{index/base_indexed_spec.rb → indexes/index_indexed_spec.rb} +3 -3
  160. data/spec/lib/{index/base_indexing_spec.rb → indexes/index_indexing_spec.rb} +19 -2
  161. data/spec/lib/{index/base_spec.rb → indexes/index_spec.rb} +6 -25
  162. data/spec/lib/{index → indexes}/redis_spec.rb +1 -1
  163. data/spec/lib/indexes_class_spec.rb +2 -2
  164. data/spec/lib/indexes_indexed_spec.rb +1 -1
  165. data/spec/lib/indexes_indexing_spec.rb +1 -1
  166. data/spec/lib/indexes_spec.rb +1 -1
  167. data/spec/lib/indexing/bundle/base_spec.rb +7 -5
  168. data/spec/lib/indexing/bundle/memory_partial_generation_speed_spec.rb +4 -4
  169. data/spec/lib/indexing/bundle/memory_spec.rb +15 -15
  170. data/spec/lib/indexing/bundle/redis_spec.rb +9 -9
  171. data/spec/lib/interfaces/live_parameters_spec.rb +5 -5
  172. data/spec/lib/loader_spec.rb +17 -19
  173. data/spec/lib/loggers/search_spec.rb +2 -2
  174. data/spec/lib/query/allocation_spec.rb +1 -1
  175. data/spec/lib/query/allocations_spec.rb +1 -1
  176. data/spec/lib/query/combination_spec.rb +4 -4
  177. data/spec/lib/query/combinations/base_spec.rb +1 -1
  178. data/spec/lib/query/combinations/memory_spec.rb +1 -1
  179. data/spec/lib/query/combinations/redis_spec.rb +1 -1
  180. data/spec/lib/query/indexes_spec.rb +7 -2
  181. data/spec/lib/query/qualifier_category_mapper_spec.rb +34 -0
  182. data/spec/lib/query/token_spec.rb +32 -53
  183. data/spec/lib/query/tokens_spec.rb +30 -35
  184. data/spec/lib/query/weights_spec.rb +16 -16
  185. data/spec/lib/rack/harakiri_spec.rb +5 -5
  186. data/spec/lib/results_spec.rb +1 -1
  187. data/spec/lib/search_spec.rb +24 -22
  188. data/spec/lib/sinatra_spec.rb +36 -0
  189. data/spec/lib/sources/base_spec.rb +1 -1
  190. data/spec/lib/sources/couch_spec.rb +9 -9
  191. data/spec/lib/sources/csv_spec.rb +7 -7
  192. data/spec/lib/sources/db_spec.rb +2 -2
  193. data/spec/lib/sources/delicious_spec.rb +5 -5
  194. data/spec/lib/sources/mongo_spec.rb +7 -7
  195. data/spec/lib/sources/wrappers/base_spec.rb +2 -2
  196. data/spec/lib/sources/wrappers/location_spec.rb +1 -1
  197. data/spec/lib/statistics_spec.rb +1 -1
  198. data/spec/lib/tokenizers/base_spec.rb +2 -2
  199. data/spec/lib/tokenizers/index_spec.rb +1 -1
  200. data/spec/lib/tokenizers/query_spec.rb +1 -1
  201. metadata +30 -30
  202. data/lib/picky/adapters/rack/query.rb +0 -65
  203. data/lib/picky/index/base.rb +0 -409
  204. data/lib/picky/index/base_indexed.rb +0 -29
  205. data/lib/picky/index/base_indexing.rb +0 -127
  206. data/lib/picky/index/memory.rb +0 -16
  207. data/lib/picky/index/redis.rb +0 -16
  208. data/lib/picky/query/qualifiers.rb +0 -76
  209. data/lib/picky/query/solr.rb +0 -60
  210. data/lib/picky/signals.rb +0 -8
  211. data/lib/picky-tasks.rb +0 -6
  212. data/lib/tasks/spec.rake +0 -11
  213. data/spec/lib/query/qualifiers_spec.rb +0 -31
@@ -1,44 +1,48 @@
1
- module Query
1
+ module Picky
2
2
 
3
- # Combinations are a number of Combination-s.
4
- #
5
- # They are the core of an allocation.
6
- # An allocation consists of a number of combinations.
7
- #
8
- module Combinations # :nodoc:all
3
+ module Query
9
4
 
10
- # Memory Combinations contain specific methods for
11
- # calculating score and ids in memory.
5
+ # Combinations are a number of Combination-s.
12
6
  #
13
- class Memory < Base
7
+ # They are the core of an allocation.
8
+ # An allocation consists of a number of combinations.
9
+ #
10
+ module Combinations # :nodoc:all
14
11
 
15
- # Returns the result ids for the allocation.
16
- #
17
- # Sorts the ids by size and & through them in the following order (sizes):
18
- # 0. [100_000, 400, 30, 2]
19
- # 1. [2, 30, 400, 100_000]
20
- # 2. (100_000 & (400 & (30 & 2))) # => result
21
- #
22
- # Note: Uses a C-optimized intersection routine (in performant.c)
23
- # for speed and memory efficiency.
12
+ # Memory Combinations contain specific methods for
13
+ # calculating score and ids in memory.
24
14
  #
25
- # Note: In the memory based version we ignore the (amount) needed hint.
26
- # We cannot use the information to speed up the algorithm, unfortunately.
27
- #
28
- def ids _, _
29
- return [] if @combinations.empty?
15
+ class Memory < Base
30
16
 
31
- # Get the ids for each combination.
17
+ # Returns the result ids for the allocation.
32
18
  #
33
- id_arrays = @combinations.inject([]) do |total, combination|
34
- total << combination.ids
35
- end
36
-
37
- # Call the optimized C algorithm.
19
+ # Sorts the ids by size and & through them in the following order (sizes):
20
+ # 0. [100_000, 400, 30, 2]
21
+ # 1. [2, 30, 400, 100_000]
22
+ # 2. (100_000 & (400 & (30 & 2))) # => result
23
+ #
24
+ # Note: Uses a C-optimized intersection routine (in performant.c)
25
+ # for speed and memory efficiency.
38
26
  #
39
- # Note: It orders the passed arrays by size.
27
+ # Note: In the memory based version we ignore the (amount) needed hint.
28
+ # We cannot use the information to speed up the algorithm, unfortunately.
40
29
  #
41
- Performant::Array.memory_efficient_intersect id_arrays
30
+ def ids _, _
31
+ return [] if @combinations.empty?
32
+
33
+ # Get the ids for each combination.
34
+ #
35
+ id_arrays = @combinations.inject([]) do |total, combination|
36
+ total << combination.ids
37
+ end
38
+
39
+ # Call the optimized C algorithm.
40
+ #
41
+ # Note: It orders the passed arrays by size.
42
+ #
43
+ Performant::Array.memory_efficient_intersect id_arrays
44
+ end
45
+
42
46
  end
43
47
 
44
48
  end
@@ -1,82 +1,86 @@
1
- module Query
1
+ module Picky
2
2
 
3
- # Combinations are a number of Combination-s.
4
- #
5
- # They are the core of an allocation.
6
- # An allocation consists of a number of combinations.
7
- #
8
- module Combinations # :nodoc:all
3
+ module Query
9
4
 
10
- # Redis Combinations contain specific methods for
11
- # calculating score and ids in memory.
5
+ # Combinations are a number of Combination-s.
12
6
  #
13
- class Redis < Base
7
+ # They are the core of an allocation.
8
+ # An allocation consists of a number of combinations.
9
+ #
10
+ module Combinations # :nodoc:all
14
11
 
15
- # Connect to the backend.
16
- #
17
- # TODO Use specific Picky Redis wrapper.
12
+ # Redis Combinations contain specific methods for
13
+ # calculating score and ids in memory.
18
14
  #
19
- def self.redis
20
- @redis ||= ::Redis.new :db => 15
21
- end
15
+ class Redis < Base
22
16
 
23
- attr_reader :redis
17
+ # Connect to the backend.
18
+ #
19
+ # TODO Use specific Picky Redis wrapper.
20
+ #
21
+ def self.redis
22
+ @redis ||= ::Redis.new :db => 15
23
+ end
24
24
 
25
- #
26
- #
27
- def initialize combinations
28
- super combinations
25
+ attr_reader :redis
29
26
 
30
- @redis = self.class.redis
31
- end
32
-
33
- # Returns the result ids for the allocation.
34
- #
35
- def ids amount, offset
36
- return [] if @combinations.empty?
27
+ #
28
+ #
29
+ def initialize combinations
30
+ super combinations
37
31
 
38
- identifiers = @combinations.inject([]) do |identifiers, combination|
39
- identifiers << "#{combination.identifier}"
32
+ @redis = self.class.redis
40
33
  end
41
34
 
42
- result_id = generate_intermediate_result_id
43
-
44
- # Intersect and store.
35
+ # Returns the result ids for the allocation.
45
36
  #
46
- redis.zinterstore result_id, identifiers
37
+ def ids amount, offset
38
+ return [] if @combinations.empty?
47
39
 
48
- # Get the stored result.
49
- #
50
- results = redis.zrange result_id, offset, (offset + amount)
40
+ identifiers = @combinations.inject([]) do |identifiers, combination|
41
+ identifiers << "#{combination.identifier}"
42
+ end
43
+
44
+ result_id = generate_intermediate_result_id
45
+
46
+ # Intersect and store.
47
+ #
48
+ redis.zinterstore result_id, identifiers
51
49
 
52
- # Delete the stored result as it was only for temporary purposes.
50
+ # Get the stored result.
51
+ #
52
+ results = redis.zrange result_id, offset, (offset + amount)
53
+
54
+ # Delete the stored result as it was only for temporary purposes.
55
+ #
56
+ # Note: I could also not delete it, but that would not be clean at all.
57
+ #
58
+ redis.del result_id
59
+
60
+ results
61
+ end
62
+
63
+ # Generate a multiple host/process safe result id.
53
64
  #
54
- # Note: I could also not delete it, but that would not be clean at all.
65
+ # Note: Generated when this class loads.
55
66
  #
56
- redis.del result_id
57
-
58
- results
59
- end
67
+ require 'socket'
68
+ def self.extract_host
69
+ @host ||= Socket.gethostname
70
+ end
71
+ def host
72
+ self.class.extract_host
73
+ end
74
+ extract_host
75
+ def pid
76
+ @pid ||= Process.pid
77
+ end
78
+ # Use the host and pid (generated lazily in child processes) for the result.
79
+ #
80
+ def generate_intermediate_result_id
81
+ :"#{host}:#{pid}:picky:result"
82
+ end
60
83
 
61
- # Generate a multiple host/process safe result id.
62
- #
63
- # Note: Generated when this class loads.
64
- #
65
- require 'socket'
66
- def self.extract_host
67
- @host ||= Socket.gethostname
68
- end
69
- def host
70
- self.class.extract_host
71
- end
72
- extract_host
73
- def pid
74
- @pid ||= Process.pid
75
- end
76
- # Use the host and pid (generated lazily in child processes) for the result.
77
- #
78
- def generate_intermediate_result_id
79
- :"#{host}:#{pid}:picky:result"
80
84
  end
81
85
 
82
86
  end
@@ -1,193 +1,208 @@
1
- module Query
2
-
3
- # The query indexes class bundles indexes given to a query.
4
- #
5
- # Example:
6
- # # If you call
7
- # Search.new dvd_index, mp3_index, video_index
8
- #
9
- # # What it does is take the three given (API-) indexes and
10
- # # bundle them in an index bundle.
11
- #
12
- class Indexes
13
-
14
- attr_reader :indexes
15
-
16
- # Creates a new Query::Indexes.
1
+ module Picky
2
+
3
+ module Query
4
+
5
+ # The query indexes class bundles indexes given to a query.
17
6
  #
18
- # Its job is to generate all possible combinations.
19
- # Note: We cannot mix memory and redis indexes just yet.
7
+ # Example:
8
+ # # If you call
9
+ # Search.new dvd_index, mp3_index, video_index
20
10
  #
21
- def initialize *indexes, combinations_type
22
- @indexes = indexes
23
- @combinations_type = combinations_type
24
- end
25
-
26
- # Returns a number of prepared (sorted, reduced etc.) allocations for the given tokens.
11
+ # # What it does is take the three given (API-) indexes and
12
+ # # bundle them in an index bundle.
27
13
  #
28
- def prepared_allocations_for tokens, weights = {}
29
- allocations = allocations_for tokens
14
+ class Indexes
30
15
 
31
- # Remove double allocations.
32
- #
33
- allocations.uniq
16
+ attr_reader :indexes
34
17
 
35
- # Score the allocations using weights as bias.
18
+ # Creates a new Query::Indexes.
36
19
  #
37
- allocations.calculate_score weights
38
-
39
- # Sort the allocations.
40
- # (allocations are sorted according to score, highest to lowest)
20
+ # Its job is to generate all possible combinations.
21
+ # Note: We cannot mix memory and redis indexes just yet.
41
22
  #
42
- allocations.sort!
23
+ def initialize *indexes, combinations_type
24
+ @indexes = indexes
25
+ @combinations_type = combinations_type
26
+ @mapper = Query::QualifierCategoryMapper.new
27
+ map_categories
28
+ end
29
+ def map_categories
30
+ @indexes.each do |index|
31
+ index.each_category do |category|
32
+ @mapper.add category
33
+ end
34
+ end
35
+ end
43
36
 
44
- # Reduce the amount of allocations.
37
+ # Returns a number of prepared (sorted, reduced etc.) allocations for the given tokens.
45
38
  #
46
- # allocations.reduce_to some_amount
39
+ def prepared_allocations_for tokens, weights = {}
40
+ allocations = allocations_for tokens
47
41
 
48
- # Remove identifiers from allocations.
49
- #
50
- # allocations.remove some_array_of_identifiers_to_remove
42
+ # Remove double allocations.
43
+ #
44
+ allocations.uniq
51
45
 
52
- allocations
53
- end
54
- # Returns a number of possible allocations for the given tokens.
55
- #
56
- def allocations_for tokens
57
- Allocations.new allocations_ary_for(tokens)
58
- end
59
- def allocations_ary_for tokens
60
- indexes.inject([]) do |allocations, index|
61
- allocations + allocation_for(tokens, index)
62
- end
63
- end
64
- def allocation_for tokens, index
65
- # Expand the combinations.
66
- #
67
- possible_combinations = tokens.possible_combinations_in index
46
+ # Score the allocations using weights as bias.
47
+ #
48
+ allocations.calculate_score weights
68
49
 
69
- # Generate all possible combinations.
70
- #
71
- expanded_combinations = expand_combinations_from possible_combinations
50
+ # Sort the allocations.
51
+ # (allocations are sorted according to score, highest to lowest)
52
+ #
53
+ allocations.sort!
72
54
 
73
- # Add the wrapped possible allocations to the ones we already have.
74
- #
75
- expanded_combinations.map! do |expanded_combination|
76
- Allocation.new @combinations_type.new(expanded_combination), index.result_identifier # TODO Do not extract result_identifier.
77
- end
78
- end
55
+ # Reduce the amount of allocations.
56
+ #
57
+ # allocations.reduce_to some_amount
79
58
 
80
- # This is the core of the search engine. No kidding.
81
- #
82
- # Gets an array of
83
- # [
84
- # [<combinations for token1>],
85
- # [<combinations for token2>],
86
- # [<combinations for token3>]
87
- # ]
88
- #
89
- # Generates all possible allocations of combinations.
90
- # [
91
- # [first combination of token1, first c of t2, first c of t3],
92
- # [first combination of token1, first c of t2, second c of t3]
93
- # ...
94
- # ]
95
- #
96
- # Generates all possible combinations of array elements:
97
- # [1,2,3] x [a,b,c] x [k,l,m] => [[1,a,k], [1,a,l], [1,a,m], [1,b,k], [1,b,l], [1,b,m], [1,c,k], ..., [3,c,m]]
98
- # Note: Also calculates the weights and sorts them accordingly.
99
- #
100
- # Note: This is a heavily optimized ruby version.
101
- #
102
- # Works like this:
103
- # [1,2,3], [a,b,c], [k,l,m] are expanded to
104
- # group mult: 1
105
- # <- single mult ->
106
- # [1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3] = 27 elements
107
- # group mult: 3
108
- # <- -> s/m
109
- # [a,a,a,b,b,b,c,c,c,a,a,a,b,b,b,c,c,c,a,a,a,b,b,b,c,c,c] = 27 elements
110
- # group mult: 9
111
- # <> s/m
112
- # [k,l,m,k,l,m,k,l,m,k,l,m,k,l,m,k,l,m,k,l,m,k,l,m,k,l,m] = 27 elements
113
- #
114
- # It is then recombined, where
115
- # [
116
- # [a,a,b,b,c,c]
117
- # [d,e,d,e,d,e]
118
- # ]
119
- # becomes
120
- # [
121
- # [a,d],
122
- # [a,e],
123
- # [b,d],
124
- # [b,e],
125
- # [c,d],
126
- # [c,e]
127
- # ]
128
- #
129
- # Note: Not using transpose as it is slower.
130
- #
131
- # Returns nil if there are no combinations.
132
- #
133
- # Note: Of course I could split this method up into smaller
134
- # ones, but I guess I am a bit sentimental.
135
- #
136
- def expand_combinations_from possible_combinations
137
- # If an element has size 0, this means one of the
138
- # tokens could not be allocated.
139
- #
140
- return [] if possible_combinations.any?(&:empty?)
59
+ # Remove identifiers from allocations.
60
+ #
61
+ # allocations.remove some_array_of_identifiers_to_remove
141
62
 
142
- # Generate the first multiplicator "with which" (well, not quite) to multiply the smallest amount of combinations.
63
+ allocations
64
+ end
65
+ # Returns a number of possible allocations for the given tokens.
143
66
  #
144
- single_mult = possible_combinations.inject(1) { |total, combinations| total * combinations.size }
67
+ def allocations_for tokens
68
+ tokens.categorize @mapper
145
69
 
146
- # Initialize a group multiplicator.
147
- #
148
- group_mult = 1
70
+ Allocations.new allocations_ary_for(tokens)
71
+ end
72
+ def allocations_ary_for tokens
73
+ indexes.inject([]) do |allocations, index|
74
+ allocations + allocation_for(tokens, index)
75
+ end
76
+ end
77
+ def allocation_for tokens, index
78
+ # Expand the combinations.
79
+ #
80
+ possible_combinations = tokens.possible_combinations_in index
149
81
 
150
- # The expanding part to line up the combinations
151
- # for later combination in allocations.
152
- #
153
- possible_combinations.collect! do |combinations|
82
+ # Generate all possible combinations.
83
+ #
84
+ expanded_combinations = expand_combinations_from possible_combinations
154
85
 
155
- # Get the size of the combinations of the first token.
86
+ # Add the wrapped possible allocations to the ones we already have.
156
87
  #
157
- combinations_size = combinations.size
88
+ expanded_combinations.map! do |expanded_combination|
89
+ Allocation.new @combinations_type.new(expanded_combination), index.result_identifier # TODO Do not extract result_identifier.
90
+ end
91
+ end
158
92
 
159
- # Special case: If there is no combination for one of the tokens.
160
- # In that case, we just use the same single mult for
161
- # the next iteration.
162
- # If there are combinations, we divide the single mult
163
- # by the number of combinations.
93
+ # This is the core of the search engine. No kidding.
94
+ #
95
+ # Gets an array of
96
+ # [
97
+ # [<combinations for token1>],
98
+ # [<combinations for token2>],
99
+ # [<combinations for token3>]
100
+ # ]
101
+ #
102
+ # Generates all possible allocations of combinations.
103
+ # [
104
+ # [first combination of token1, first c of t2, first c of t3],
105
+ # [first combination of token1, first c of t2, second c of t3]
106
+ # ...
107
+ # ]
108
+ #
109
+ # Generates all possible combinations of array elements:
110
+ # [1,2,3] x [a,b,c] x [k,l,m] => [[1,a,k], [1,a,l], [1,a,m], [1,b,k], [1,b,l], [1,b,m], [1,c,k], ..., [3,c,m]]
111
+ # Note: Also calculates the weights and sorts them accordingly.
112
+ #
113
+ # Note: This is a heavily optimized ruby version.
114
+ #
115
+ # Works like this:
116
+ # [1,2,3], [a,b,c], [k,l,m] are expanded to
117
+ # group mult: 1
118
+ # <- single mult ->
119
+ # [1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3] = 27 elements
120
+ # group mult: 3
121
+ # <- -> s/m
122
+ # [a,a,a,b,b,b,c,c,c,a,a,a,b,b,b,c,c,c,a,a,a,b,b,b,c,c,c] = 27 elements
123
+ # group mult: 9
124
+ # <> s/m
125
+ # [k,l,m,k,l,m,k,l,m,k,l,m,k,l,m,k,l,m,k,l,m,k,l,m,k,l,m] = 27 elements
126
+ #
127
+ # It is then recombined, where
128
+ # [
129
+ # [a,a,b,b,c,c]
130
+ # [d,e,d,e,d,e]
131
+ # ]
132
+ # becomes
133
+ # [
134
+ # [a,d],
135
+ # [a,e],
136
+ # [b,d],
137
+ # [b,e],
138
+ # [c,d],
139
+ # [c,e]
140
+ # ]
141
+ #
142
+ # Note: Not using transpose as it is slower.
143
+ #
144
+ # Returns nil if there are no combinations.
145
+ #
146
+ # Note: Of course I could split this method up into smaller
147
+ # ones, but I guess I am a bit sentimental.
148
+ #
149
+ def expand_combinations_from possible_combinations
150
+ # If an element has size 0, this means one of the
151
+ # tokens could not be allocated.
164
152
  #
165
- single_mult /= combinations_size unless combinations_size.zero?
153
+ return [] if possible_combinations.any?(&:empty?)
166
154
 
167
- # Expand each combination by the single mult:
168
- # [a,b,c]
169
- # [a,a,a, b,b,b, c,c,c]
170
- # Then, expand the result by the group mult:
171
- # [a,a,a,b,b,b,c,c,c, a,a,a,b,b,b,c,c,c, a,a,a,b,b,b,c,c,c]
155
+ # Generate the first multiplicator "with which" (well, not quite) to multiply the smallest amount of combinations.
172
156
  #
173
- combinations = combinations.inject([]) do |total, combination|
174
- total + Array.new(single_mult, combination)
175
- end * group_mult
157
+ single_mult = possible_combinations.inject(1) { |total, combinations| total * combinations.size }
176
158
 
177
- # Multiply the group mult by the combinations size,
178
- # since the next combinations' single mult is smaller
179
- # and we need to adjust for that.
159
+ # Initialize a group multiplicator.
180
160
  #
181
- group_mult = group_mult * combinations_size
161
+ group_mult = 1
182
162
 
183
- # Return the combinations.
163
+ # The expanding part to line up the combinations
164
+ # for later combination in allocations.
184
165
  #
185
- combinations
166
+ possible_combinations.collect! do |combinations|
167
+
168
+ # Get the size of the combinations of the first token.
169
+ #
170
+ combinations_size = combinations.size
171
+
172
+ # Special case: If there is no combination for one of the tokens.
173
+ # In that case, we just use the same single mult for
174
+ # the next iteration.
175
+ # If there are combinations, we divide the single mult
176
+ # by the number of combinations.
177
+ #
178
+ single_mult /= combinations_size unless combinations_size.zero?
179
+
180
+ # Expand each combination by the single mult:
181
+ # [a,b,c]
182
+ # [a,a,a, b,b,b, c,c,c]
183
+ # Then, expand the result by the group mult:
184
+ # [a,a,a,b,b,b,c,c,c, a,a,a,b,b,b,c,c,c, a,a,a,b,b,b,c,c,c]
185
+ #
186
+ combinations = combinations.inject([]) do |total, combination|
187
+ total + Array.new(single_mult, combination)
188
+ end * group_mult
189
+
190
+ # Multiply the group mult by the combinations size,
191
+ # since the next combinations' single mult is smaller
192
+ # and we need to adjust for that.
193
+ #
194
+ group_mult = group_mult * combinations_size
195
+
196
+ # Return the combinations.
197
+ #
198
+ combinations
199
+ end
200
+
201
+ return [] if possible_combinations.empty?
202
+
203
+ possible_combinations.shift.zip *possible_combinations
186
204
  end
187
205
 
188
- return [] if possible_combinations.empty?
189
-
190
- possible_combinations.shift.zip *possible_combinations
191
206
  end
192
207
 
193
208
  end
@@ -0,0 +1,43 @@
1
+ module Picky
2
+
3
+ # coding: utf-8
4
+ #
5
+ module Query
6
+
7
+ # Collection class for qualifiers.
8
+ #
9
+ class QualifierCategoryMapper # :nodoc:all
10
+
11
+ attr_reader :mapping
12
+
13
+ #
14
+ #
15
+ def initialize
16
+ @mapping = {}
17
+ end
18
+
19
+ #
20
+ #
21
+ def add category
22
+ category.qualifiers.each do |qualifier|
23
+ sym_qualifier = qualifier.to_sym
24
+ warn %Q{Warning: Qualifier "#{qualifier}" already mapped to category #{mapping[sym_qualifier].identifier} (ambiguous qualifier mapping).} if mapping.has_key? sym_qualifier
25
+ mapping[sym_qualifier] = category
26
+ end
27
+ end
28
+
29
+ # Normalizes the given qualifier.
30
+ #
31
+ # Returns nil if it is not allowed, the normalized qualifier if it is.
32
+ #
33
+ def map qualifier
34
+ return nil if qualifier.blank?
35
+
36
+ @mapping[qualifier.to_sym]
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+
43
+ end