/
bundle.rb
176 lines (157 loc) · 5.15 KB
/
bundle.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
module Picky
# A Bundle is a number of indexes
# per [index, category] combination.
#
# At most, there are three indexes:
# * *core* index (always used)
# * *weights* index (always used)
# * *similarity* index (used with similarity)
#
# In Picky, indexing is separated from the index
# handling itself through a parallel structure.
#
# Both use methods provided by this base class, but
# have very different goals:
#
# * *Indexing*::*Bundle*::*Base* is just concerned with creating index
# files / redis entries and providing helper functions to e.g. check
# the indexes.
#
# * *Index*::*Bundle*::*Base* is concerned with loading these index files into
# memory / redis and looking up search data as fast as possible.
#
class Bundle
attr_reader :name,
:category
attr_accessor :inverted,
:weights,
:similarity,
:configuration,
:realtime,
:backend_inverted,
:backend_weights,
:backend_similarity,
:backend_configuration,
:weights_strategy,
:partial_strategy,
:similarity_strategy
delegate :[], :[]=, :to => :configuration
delegate :index_directory, :to => :category
def initialize name, category, weights_strategy, partial_strategy, similarity_strategy, options = {}
@name = name
@category = category
@weights_strategy = weights_strategy
@partial_strategy = partial_strategy
@similarity_strategy = similarity_strategy
@key_format = options.delete :key_format
@backend = options.delete :backend
reset_backend
end
def identifier
@identifier ||= :"#{category.identifier}:#{name}"
end
# If no specific backend has been set,
# uses the category's backend.
#
def backend
@backend || category.backend
end
# Initializes all necessary indexes from the backend.
#
def reset_backend
# Extract specific indexes from backend.
#
@backend_inverted = backend.create_inverted self
@backend_weights = backend.create_weights self
@backend_similarity = backend.create_similarity self
@backend_configuration = backend.create_configuration self
@backend_realtime = backend.create_realtime self
# Initial indexes.
#
# Note that if the weights strategy doesn't need to be saved,
# the strategy itself pretends to be an index.
#
@inverted = @backend_inverted.initial
@weights = @weights_strategy.saved?? @backend_weights.initial : @weights_strategy
@similarity = @backend_similarity.initial
@configuration = @backend_configuration.initial
@realtime = @backend_realtime.initial
end
# "Empties" the index(es) by getting a new empty
# internal backend instance.
#
def empty
empty_inverted
empty_weights
empty_similarity
empty_configuration
empty_realtime
end
def empty_inverted
@inverted = @backend_inverted.empty
end
def empty_weights
# THINK about this. Perhaps the strategies should implement the backend methods?
#
@weights = @weights_strategy.saved?? @backend_weights.empty : @weights_strategy
end
def empty_similarity
@similarity = @backend_similarity.empty
end
def empty_configuration
@configuration = @backend_configuration.empty
end
def empty_realtime
@realtime = @backend_realtime.empty
end
# Get a list of similar texts.
#
# Note: Does not return itself.
#
def similar text
code = similarity_strategy.encoded text
return [] unless code
similar_codes = @similarity[code]
if similar_codes.blank?
[] # Return a simple array.
else
similar_codes = similar_codes.dup
similar_codes.delete text
similar_codes
end
end
# If a key format is set, use it, else delegate to the category.
#
def key_format
@key_format || @category.key_format
end
# Path and partial filename of a specific subindex.
#
# Subindexes are:
# * inverted index
# * weights index
# * partial index
# * similarity index
#
# Returns just the part without subindex type,
# if none given.
#
def index_path type = nil
::File.join index_directory, "#{category.name}_#{name}#{ "_#{type}" if type }"
end
# Delete all index files.
#
def delete
@backend_inverted.delete if @backend_inverted.respond_to? :delete
# THINK about this. Perhaps the strategies should implement the backend methods?
#
@backend_weights.delete if @backend_weights.respond_to?(:delete) && @weights_strategy.saved?
@backend_similarity.delete if @backend_similarity.respond_to? :delete
@backend_configuration.delete if @backend_configuration.respond_to? :delete
@backend_realtime.delete if @backend_realtime.respond_to? :delete
end
def to_s
"#{self.class}(#{identifier})"
end
end
end