picky 0.0.0 → 0.0.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.
- data/bin/picky +14 -0
- data/lib/bundling.rb +10 -0
- data/lib/constants.rb +9 -0
- data/lib/deployment.rb +212 -0
- data/lib/picky/application.rb +40 -0
- data/lib/picky/cacher/convenience.rb +3 -0
- data/lib/picky/cacher/generator.rb +17 -0
- data/lib/picky/cacher/partial/default.rb +7 -0
- data/lib/picky/cacher/partial/none.rb +19 -0
- data/lib/picky/cacher/partial/strategy.rb +7 -0
- data/lib/picky/cacher/partial/subtoken.rb +91 -0
- data/lib/picky/cacher/partial_generator.rb +15 -0
- data/lib/picky/cacher/similarity/default.rb +7 -0
- data/lib/picky/cacher/similarity/double_levenshtone.rb +73 -0
- data/lib/picky/cacher/similarity/none.rb +25 -0
- data/lib/picky/cacher/similarity/strategy.rb +7 -0
- data/lib/picky/cacher/similarity_generator.rb +15 -0
- data/lib/picky/cacher/weights/default.rb +7 -0
- data/lib/picky/cacher/weights/logarithmic.rb +39 -0
- data/lib/picky/cacher/weights/strategy.rb +7 -0
- data/lib/picky/cacher/weights_generator.rb +15 -0
- data/lib/picky/configuration/configuration.rb +13 -0
- data/lib/picky/configuration/field.rb +68 -0
- data/lib/picky/configuration/indexes.rb +60 -0
- data/lib/picky/configuration/queries.rb +32 -0
- data/lib/picky/configuration/type.rb +52 -0
- data/lib/picky/cores.rb +101 -0
- data/lib/picky/db/configuration.rb +23 -0
- data/lib/picky/ext/ruby19/extconf.rb +7 -0
- data/lib/picky/ext/ruby19/performant.c +339 -0
- data/lib/picky/extensions/array.rb +45 -0
- data/lib/picky/extensions/hash.rb +11 -0
- data/lib/picky/extensions/module.rb +15 -0
- data/lib/picky/extensions/symbol.rb +18 -0
- data/lib/picky/generator.rb +156 -0
- data/lib/picky/helpers/cache.rb +23 -0
- data/lib/picky/helpers/gc.rb +11 -0
- data/lib/picky/helpers/measuring.rb +45 -0
- data/lib/picky/helpers/search.rb +27 -0
- data/lib/picky/index/bundle.rb +328 -0
- data/lib/picky/index/category.rb +109 -0
- data/lib/picky/index/combined.rb +38 -0
- data/lib/picky/index/type.rb +30 -0
- data/lib/picky/indexers/base.rb +77 -0
- data/lib/picky/indexers/default.rb +3 -0
- data/lib/picky/indexers/field.rb +13 -0
- data/lib/picky/indexers/no_source_specified_error.rb +5 -0
- data/lib/picky/indexers/solr.rb +60 -0
- data/lib/picky/indexes.rb +180 -0
- data/lib/picky/initializers/ext.rb +6 -0
- data/lib/picky/initializers/mysql.rb +22 -0
- data/lib/picky/loader.rb +287 -0
- data/lib/picky/loggers/search.rb +19 -0
- data/lib/picky/performant/array.rb +23 -0
- data/lib/picky/query/allocation.rb +82 -0
- data/lib/picky/query/allocations.rb +131 -0
- data/lib/picky/query/base.rb +124 -0
- data/lib/picky/query/combination.rb +69 -0
- data/lib/picky/query/combinations.rb +106 -0
- data/lib/picky/query/combinator.rb +92 -0
- data/lib/picky/query/full.rb +15 -0
- data/lib/picky/query/live.rb +22 -0
- data/lib/picky/query/qualifiers.rb +73 -0
- data/lib/picky/query/solr.rb +77 -0
- data/lib/picky/query/token.rb +215 -0
- data/lib/picky/query/tokens.rb +102 -0
- data/lib/picky/query/weigher.rb +159 -0
- data/lib/picky/query/weights.rb +55 -0
- data/lib/picky/rack/harakiri.rb +37 -0
- data/lib/picky/results/base.rb +103 -0
- data/lib/picky/results/full.rb +19 -0
- data/lib/picky/results/live.rb +19 -0
- data/lib/picky/routing.rb +165 -0
- data/lib/picky/signals.rb +11 -0
- data/lib/picky/solr/schema_generator.rb +73 -0
- data/lib/picky/sources/base.rb +19 -0
- data/lib/picky/sources/csv.rb +30 -0
- data/lib/picky/sources/db.rb +77 -0
- data/lib/picky/tokenizers/base.rb +130 -0
- data/lib/picky/tokenizers/default.rb +3 -0
- data/lib/picky/tokenizers/index.rb +73 -0
- data/lib/picky/tokenizers/query.rb +70 -0
- data/lib/picky/umlaut_substituter.rb +21 -0
- data/lib/picky-tasks.rb +6 -0
- data/lib/picky.rb +18 -0
- data/lib/tasks/application.rake +5 -0
- data/lib/tasks/cache.rake +53 -0
- data/lib/tasks/framework.rake +4 -0
- data/lib/tasks/index.rake +29 -0
- data/lib/tasks/server.rake +48 -0
- data/lib/tasks/shortcuts.rake +13 -0
- data/lib/tasks/solr.rake +36 -0
- data/lib/tasks/spec.rake +11 -0
- data/lib/tasks/statistics.rake +13 -0
- data/lib/tasks/try.rake +29 -0
- data/prototype_project/Gemfile +23 -0
- data/prototype_project/Rakefile +1 -0
- data/prototype_project/app/README +6 -0
- data/prototype_project/app/application.rb +50 -0
- data/prototype_project/app/application.ru +29 -0
- data/prototype_project/app/db.yml +10 -0
- data/prototype_project/app/logging.rb +20 -0
- data/prototype_project/app/unicorn.ru +10 -0
- data/prototype_project/log/README +1 -0
- data/prototype_project/script/console +34 -0
- data/prototype_project/tmp/README +0 -0
- data/prototype_project/tmp/pids/README +0 -0
- data/spec/ext/performant_spec.rb +64 -0
- data/spec/lib/application_spec.rb +61 -0
- data/spec/lib/cacher/partial/subtoken_spec.rb +89 -0
- data/spec/lib/cacher/partial_generator_spec.rb +35 -0
- data/spec/lib/cacher/similarity/double_levenshtone_spec.rb +60 -0
- data/spec/lib/cacher/similarity/none_spec.rb +23 -0
- data/spec/lib/cacher/similarity_generator_spec.rb +22 -0
- data/spec/lib/cacher/weights/logarithmic_spec.rb +30 -0
- data/spec/lib/cacher/weights_generator_spec.rb +21 -0
- data/spec/lib/configuration/configuration_spec.rb +38 -0
- data/spec/lib/configuration/type_spec.rb +49 -0
- data/spec/lib/configuration_spec.rb +8 -0
- data/spec/lib/cores_spec.rb +65 -0
- data/spec/lib/extensions/array_spec.rb +37 -0
- data/spec/lib/extensions/hash_spec.rb +11 -0
- data/spec/lib/extensions/module_spec.rb +27 -0
- data/spec/lib/extensions/symbol_spec.rb +85 -0
- data/spec/lib/generator_spec.rb +135 -0
- data/spec/lib/helpers/cache_spec.rb +35 -0
- data/spec/lib/helpers/gc_spec.rb +71 -0
- data/spec/lib/helpers/measuring_spec.rb +18 -0
- data/spec/lib/helpers/search_spec.rb +50 -0
- data/spec/lib/index/bundle_partial_generation_speed_spec.rb +47 -0
- data/spec/lib/index/bundle_spec.rb +260 -0
- data/spec/lib/index/category_spec.rb +203 -0
- data/spec/lib/indexers/base_spec.rb +73 -0
- data/spec/lib/indexers/field_spec.rb +20 -0
- data/spec/lib/loader_spec.rb +48 -0
- data/spec/lib/loggers/search_spec.rb +19 -0
- data/spec/lib/performant/array_spec.rb +13 -0
- data/spec/lib/query/allocation_spec.rb +194 -0
- data/spec/lib/query/allocations_spec.rb +336 -0
- data/spec/lib/query/base_spec.rb +104 -0
- data/spec/lib/query/combination_spec.rb +90 -0
- data/spec/lib/query/combinations_spec.rb +83 -0
- data/spec/lib/query/combinator_spec.rb +112 -0
- data/spec/lib/query/full_spec.rb +22 -0
- data/spec/lib/query/live_spec.rb +61 -0
- data/spec/lib/query/qualifiers_spec.rb +31 -0
- data/spec/lib/query/solr_spec.rb +51 -0
- data/spec/lib/query/token_spec.rb +297 -0
- data/spec/lib/query/tokens_spec.rb +189 -0
- data/spec/lib/query/weights_spec.rb +47 -0
- data/spec/lib/results/base_spec.rb +233 -0
- data/spec/lib/routing_spec.rb +318 -0
- data/spec/lib/solr/schema_generator_spec.rb +42 -0
- data/spec/lib/sources/db_spec.rb +91 -0
- data/spec/lib/tokenizers/base_spec.rb +61 -0
- data/spec/lib/tokenizers/index_spec.rb +51 -0
- data/spec/lib/tokenizers/query_spec.rb +105 -0
- data/spec/lib/umlaut_substituter_spec.rb +84 -0
- data/spec/specific/speed_spec.rb +55 -0
- metadata +371 -15
- data/README.textile +0 -9
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
module Index
|
|
2
|
+
|
|
3
|
+
# An index category holds a full and a partial index for a given field.
|
|
4
|
+
#
|
|
5
|
+
# For example an index category for names holds a full and
|
|
6
|
+
# a partial index bundle for names.
|
|
7
|
+
#
|
|
8
|
+
class Category
|
|
9
|
+
|
|
10
|
+
attr_reader :name, :type, :full, :partial
|
|
11
|
+
|
|
12
|
+
#
|
|
13
|
+
#
|
|
14
|
+
def initialize name, type, options = {}
|
|
15
|
+
@name = name
|
|
16
|
+
@type = type
|
|
17
|
+
|
|
18
|
+
partial = options[:partial] || Cacher::Partial::Default
|
|
19
|
+
weights = options[:weights] || Cacher::Weights::Default
|
|
20
|
+
similarity = options[:similarity] || Cacher::Similarity::Default
|
|
21
|
+
|
|
22
|
+
@full = options[:full_bundle] || Bundle.new(:full, self, type, Cacher::Partial::None.new, weights, similarity)
|
|
23
|
+
@partial = options[:partial_bundle] || Bundle.new(:partial, self, type, partial, weights, Cacher::Similarity::None.new)
|
|
24
|
+
|
|
25
|
+
@full = options[:full_lambda].call(@full, @partial) if options[:full_lambda]
|
|
26
|
+
@partial = options[:partial_lambda].call(@full, @partial) if options[:partial_lambda]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Loads the index from cache.
|
|
30
|
+
#
|
|
31
|
+
def load_from_cache
|
|
32
|
+
full.load
|
|
33
|
+
partial.load
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def identifier
|
|
37
|
+
"#{type.name}:#{name}"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Generates all caches for this category.
|
|
41
|
+
#
|
|
42
|
+
def generate_caches
|
|
43
|
+
exclaim "#{Time.now}: Loading data from db for #{identifier}."
|
|
44
|
+
generate_caches_from_db
|
|
45
|
+
exclaim "#{Time.now}: Generating partial for #{identifier}."
|
|
46
|
+
generate_partial
|
|
47
|
+
exclaim "#{Time.now}: Generating caches from memory for #{identifier}."
|
|
48
|
+
generate_caches_from_memory
|
|
49
|
+
exclaim "#{Time.now}: Dumping all caches for #{identifier}."
|
|
50
|
+
dump_caches
|
|
51
|
+
end
|
|
52
|
+
def generate_caches_from_db
|
|
53
|
+
full.generate_caches_from_db
|
|
54
|
+
end
|
|
55
|
+
def generate_partial
|
|
56
|
+
partial.generate_partial_from full.index
|
|
57
|
+
end
|
|
58
|
+
def generate_caches_from_memory
|
|
59
|
+
partial.generate_caches_from_memory
|
|
60
|
+
end
|
|
61
|
+
def dump_caches
|
|
62
|
+
full.dump
|
|
63
|
+
partial.dump
|
|
64
|
+
end
|
|
65
|
+
def exclaim text
|
|
66
|
+
puts text
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Used for testing.
|
|
70
|
+
#
|
|
71
|
+
def generate_indexes_from_full_index
|
|
72
|
+
generate_derived_full
|
|
73
|
+
generate_partial
|
|
74
|
+
generate_derived_partial
|
|
75
|
+
end
|
|
76
|
+
def generate_derived_full
|
|
77
|
+
full.generate_derived
|
|
78
|
+
end
|
|
79
|
+
def generate_derived_partial
|
|
80
|
+
partial.generate_derived
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Gets the weight for this token's text.
|
|
84
|
+
#
|
|
85
|
+
def weight token
|
|
86
|
+
bundle_for(token).weight token.text
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Gets the ids for this token's text.
|
|
90
|
+
#
|
|
91
|
+
def ids token
|
|
92
|
+
bundle_for(token).ids token.text
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Returns the right index bundle for this token.
|
|
96
|
+
#
|
|
97
|
+
def bundle_for token
|
|
98
|
+
token.partial? ? partial : full
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
#
|
|
102
|
+
#
|
|
103
|
+
def combination_for token
|
|
104
|
+
weight(token) && ::Query::Combination.new(token, self)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
#
|
|
3
|
+
module Index
|
|
4
|
+
|
|
5
|
+
#
|
|
6
|
+
#
|
|
7
|
+
class Combined < Bundle
|
|
8
|
+
|
|
9
|
+
delegate :similar,
|
|
10
|
+
:identifier,
|
|
11
|
+
:name,
|
|
12
|
+
:to => :@full
|
|
13
|
+
delegate :type,
|
|
14
|
+
:category,
|
|
15
|
+
:weight,
|
|
16
|
+
:generate_partial_from,
|
|
17
|
+
:generate_caches_from_memory,
|
|
18
|
+
:generate_derived,
|
|
19
|
+
:dump,
|
|
20
|
+
:load,
|
|
21
|
+
:to => :@partial
|
|
22
|
+
|
|
23
|
+
def initialize full, partial
|
|
24
|
+
@full = full
|
|
25
|
+
@partial = partial
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def ids text
|
|
29
|
+
@full.ids(text) + @partial.ids(text)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def weight text
|
|
33
|
+
[@full.weight(text) || 0, @partial.weight(text) || 0].max
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Index
|
|
2
|
+
|
|
3
|
+
# This class is for multiple types.
|
|
4
|
+
#
|
|
5
|
+
# For example, you could have types books, isbn.
|
|
6
|
+
#
|
|
7
|
+
class Type
|
|
8
|
+
|
|
9
|
+
attr_reader :name, :result_type, :categories, :combinator
|
|
10
|
+
|
|
11
|
+
each_delegate :generate_caches, :load_from_cache, :to => :categories
|
|
12
|
+
|
|
13
|
+
# TODO Use config
|
|
14
|
+
#
|
|
15
|
+
def initialize name, result_type, ignore_unassigned_tokens, *categories
|
|
16
|
+
@name = name
|
|
17
|
+
@result_type = result_type # TODO Move.
|
|
18
|
+
@categories = categories # for each_delegate
|
|
19
|
+
@combinator = Query::Combinator.new @categories, :ignore_unassigned_tokens => ignore_unassigned_tokens # TODO pass this in?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
#
|
|
23
|
+
#
|
|
24
|
+
def possible_combinations token
|
|
25
|
+
@combinator.possible_combinations_for token
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
module Indexers
|
|
3
|
+
# Indexer.
|
|
4
|
+
#
|
|
5
|
+
# 1. Gets data from the original table and copies it into a "snapshot table".
|
|
6
|
+
# 3. Processes the data. I.e. takes the snapshot table data words and tokenizes etc. them. Writes the result into a txt file.
|
|
7
|
+
#
|
|
8
|
+
class Base
|
|
9
|
+
|
|
10
|
+
def initialize type, field
|
|
11
|
+
@type = type
|
|
12
|
+
@field = field
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Convenience method for getting the right Tokenizer.
|
|
16
|
+
#
|
|
17
|
+
def tokenizer
|
|
18
|
+
@field.tokenizer
|
|
19
|
+
end
|
|
20
|
+
# Convenience methods for user subclasses.
|
|
21
|
+
#
|
|
22
|
+
def search_index_file_name
|
|
23
|
+
@field.search_index_file_name
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Executes the specific strategy.
|
|
27
|
+
#
|
|
28
|
+
def index
|
|
29
|
+
process
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Get the source where the data is taken from.
|
|
33
|
+
#
|
|
34
|
+
def source
|
|
35
|
+
@field.source || raise_no_source
|
|
36
|
+
end
|
|
37
|
+
def raise_no_source
|
|
38
|
+
raise NoSourceSpecifiedException.new "No source given for #{@type.name}:#{@field.name}."
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Selects the original id (indexed id) and a column to process. The column data is called "token".
|
|
42
|
+
#
|
|
43
|
+
def process
|
|
44
|
+
comma = ?,
|
|
45
|
+
newline = ?\n
|
|
46
|
+
|
|
47
|
+
File.open(search_index_file_name, 'w:binary') do |file|
|
|
48
|
+
chunked do |indexed_id, text|
|
|
49
|
+
tokenizer.tokenize(text).each do |token_text|
|
|
50
|
+
file.write indexed_id
|
|
51
|
+
file.write comma
|
|
52
|
+
file.write token_text
|
|
53
|
+
file.write newline
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
# Split original data into chunks.
|
|
59
|
+
#
|
|
60
|
+
def chunked
|
|
61
|
+
(0..source.count(@type)).step(chunksize) do |offset|
|
|
62
|
+
indexing_message offset
|
|
63
|
+
data = source.harvest @type, @field, offset, chunksize
|
|
64
|
+
data.each do |indexed_id, text|
|
|
65
|
+
next unless text
|
|
66
|
+
text.force_encoding 'utf-8' # TODO Still needed?
|
|
67
|
+
yield indexed_id, text
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def indexing_message offset
|
|
73
|
+
puts "#{Time.now}: Indexing #{@type.name}:#{@field.name}:#{@field.indexed_name} beginning at #{offset}."
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
#
|
|
3
|
+
require 'rsolr'
|
|
4
|
+
module Indexers
|
|
5
|
+
# This is an indexer in its own right.
|
|
6
|
+
#
|
|
7
|
+
# TODO Perhaps merge with the existing indexer.
|
|
8
|
+
#
|
|
9
|
+
class Solr
|
|
10
|
+
|
|
11
|
+
attr_reader :type, :fields, :solr
|
|
12
|
+
|
|
13
|
+
# Takes a Configuration::Type.
|
|
14
|
+
#
|
|
15
|
+
def initialize type
|
|
16
|
+
@type = type
|
|
17
|
+
@fields = type.solr_fields.map(&:name).map(&:to_sym)
|
|
18
|
+
@solr = RSolr.connect
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# TODO Rewrite such that it works in batches.
|
|
22
|
+
#
|
|
23
|
+
def index
|
|
24
|
+
puts "#{Time.now}: Indexing solr for #{type.name}:#{fields.join(', ')}"
|
|
25
|
+
statement = "SELECT indexed_id, #{fields.join(',')} FROM #{type.snapshot_table_name}"
|
|
26
|
+
|
|
27
|
+
# TODO Rewrite.
|
|
28
|
+
#
|
|
29
|
+
DB.connect
|
|
30
|
+
results = DB.connection.execute statement
|
|
31
|
+
|
|
32
|
+
return unless results # TODO check
|
|
33
|
+
|
|
34
|
+
type_name = @type.name.to_s
|
|
35
|
+
|
|
36
|
+
solr.delete_by_query "type:#{type_name}"
|
|
37
|
+
solr.commit
|
|
38
|
+
|
|
39
|
+
documents = []
|
|
40
|
+
|
|
41
|
+
results.each do |indexed_id, *values|
|
|
42
|
+
values.each &:downcase!
|
|
43
|
+
documents << hashed(values).merge(:id => indexed_id, :type => type_name)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
solr.add documents
|
|
47
|
+
solr.commit
|
|
48
|
+
solr.optimize
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def hashed values
|
|
52
|
+
result = {}
|
|
53
|
+
fields.zip(values).each do |field, value|
|
|
54
|
+
result[field] = value
|
|
55
|
+
end
|
|
56
|
+
result
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
module Indexes
|
|
2
|
+
|
|
3
|
+
mattr_accessor :configuration, :types, :type_mapping
|
|
4
|
+
|
|
5
|
+
# Takes a snapshot of the originating table.
|
|
6
|
+
#
|
|
7
|
+
def self.take_snapshot *args
|
|
8
|
+
configuration.take_snapshot *args
|
|
9
|
+
end
|
|
10
|
+
# Runs the indexers in parallel (index + cache).
|
|
11
|
+
#
|
|
12
|
+
def self.index
|
|
13
|
+
Indexes.take_snapshot
|
|
14
|
+
|
|
15
|
+
# Run in parallel.
|
|
16
|
+
#
|
|
17
|
+
puts "Indexing using #{Cores.max_processors} processors."
|
|
18
|
+
Cores.forked self.fields, :randomly => true do |field|
|
|
19
|
+
# Reestablish DB connection.
|
|
20
|
+
DB.connect # TODO Rewrite!
|
|
21
|
+
field.index
|
|
22
|
+
field.cache
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
def self.index_solr
|
|
26
|
+
configuration.index_solr
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Returns an array of fields.
|
|
30
|
+
#
|
|
31
|
+
# TODO Rewrite.
|
|
32
|
+
#
|
|
33
|
+
def self.fields
|
|
34
|
+
result = []
|
|
35
|
+
configuration.types.each do |type|
|
|
36
|
+
type.fields.inject(result) do |total, field|
|
|
37
|
+
total << field
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
result
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
#
|
|
44
|
+
#
|
|
45
|
+
# TODO Rewrite.
|
|
46
|
+
#
|
|
47
|
+
def self.find type_name, field_name
|
|
48
|
+
type_name = type_name.to_sym
|
|
49
|
+
field_name = field_name.to_sym
|
|
50
|
+
configuration.types.each do |type|
|
|
51
|
+
next unless type.name == type_name
|
|
52
|
+
type.fields.each do |field|
|
|
53
|
+
next unless field.name == field_name
|
|
54
|
+
return field
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Backup / Restore.
|
|
60
|
+
#
|
|
61
|
+
def self.backup_caches
|
|
62
|
+
each_category do |category|
|
|
63
|
+
category.full.backup
|
|
64
|
+
category.partial.backup
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
def self.restore_caches
|
|
68
|
+
each_category do |category|
|
|
69
|
+
category.full.restore
|
|
70
|
+
category.partial.restore
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Use these if you need to index / cache a single index.
|
|
75
|
+
#
|
|
76
|
+
def self.generate_index_only type_name, field_name
|
|
77
|
+
Indexes.configuration.types.each do |type|
|
|
78
|
+
next unless type_name == type.name
|
|
79
|
+
type.fields.each do |field|
|
|
80
|
+
field.index if field_name == field.name
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
def self.generate_cache_only type_name, category_name
|
|
85
|
+
Indexes.each do |type|
|
|
86
|
+
next unless type_name == type.name
|
|
87
|
+
type.categories.each do |category|
|
|
88
|
+
category.generate_caches if category_name == category.name
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Runs the index cache generation.
|
|
94
|
+
#
|
|
95
|
+
# TODO Needed?
|
|
96
|
+
#
|
|
97
|
+
def self.generate_caches
|
|
98
|
+
each &:generate_caches
|
|
99
|
+
end
|
|
100
|
+
# Loads all indexes from the caches.
|
|
101
|
+
#
|
|
102
|
+
def self.load_from_cache
|
|
103
|
+
each &:load_from_cache
|
|
104
|
+
end
|
|
105
|
+
def self.reload
|
|
106
|
+
load_from_cache
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Checks if the caches are there.
|
|
110
|
+
#
|
|
111
|
+
def self.check_caches
|
|
112
|
+
each do |type|
|
|
113
|
+
type.categories.each do |category|
|
|
114
|
+
category.full.raise_unless_cache_exists
|
|
115
|
+
category.partial.raise_unless_cache_exists
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Removes the cache files.
|
|
121
|
+
#
|
|
122
|
+
def self.clear_caches
|
|
123
|
+
each do |type|
|
|
124
|
+
type.categories.each do |category|
|
|
125
|
+
category.full.delete_all
|
|
126
|
+
category.partial.delete_all
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Creates the directory structure for the indexes.
|
|
132
|
+
#
|
|
133
|
+
# TODO Should be on type?
|
|
134
|
+
#
|
|
135
|
+
def self.create_directory_structure
|
|
136
|
+
each_bundle do |full, partial|
|
|
137
|
+
full.create_directory
|
|
138
|
+
partial.create_directory
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
#
|
|
143
|
+
#
|
|
144
|
+
def self.clear
|
|
145
|
+
self.types = []
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def self.each &block
|
|
150
|
+
types.each &block
|
|
151
|
+
end
|
|
152
|
+
def self.each_category &block
|
|
153
|
+
each do |type|
|
|
154
|
+
type.categories.each &block
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
def self.each_bundle
|
|
158
|
+
each_category do |category|
|
|
159
|
+
yield category.full, category.partial
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Loads all index definitions.
|
|
164
|
+
#
|
|
165
|
+
def self.setup
|
|
166
|
+
self.types ||= []
|
|
167
|
+
self.type_mapping ||= {}
|
|
168
|
+
configuration.types.each do |type|
|
|
169
|
+
add type.generate
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
def self.add type
|
|
173
|
+
self.type_mapping[type.name] = type
|
|
174
|
+
self.types << type
|
|
175
|
+
end
|
|
176
|
+
def self.[] type_name
|
|
177
|
+
self.type_mapping[type_name]
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Wrapper for the mysql adapter method execute
|
|
2
|
+
# to handle the 8 hours disconnect problem.
|
|
3
|
+
# (http://www.mysql.fr/search/?q=autoreconnect)
|
|
4
|
+
#
|
|
5
|
+
ActiveRecord::ConnectionAdapters::MysqlAdapter.module_eval do
|
|
6
|
+
def execute_with_retry_once(sql, name = nil)
|
|
7
|
+
retried = false
|
|
8
|
+
begin
|
|
9
|
+
execute_without_retry_once(sql, name)
|
|
10
|
+
rescue ActiveRecord::StatementInvalid => statement_invalid_exception
|
|
11
|
+
# Our database connection has gone away, reconnect and retry this method
|
|
12
|
+
#
|
|
13
|
+
reconnect!
|
|
14
|
+
unless retried
|
|
15
|
+
retried = true
|
|
16
|
+
retry
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
alias_method_chain :execute, :retry_once
|
|
22
|
+
end
|