stretchy-model 0.6.0 → 0.6.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +2 -1
- data/README.md +28 -10
- data/Rakefile +56 -0
- data/containers/Dockerfile.opensearch +4 -3
- data/docker-compose.yml +32 -19
- data/docs/.nojekyll +0 -0
- data/docs/README.md +147 -0
- data/docs/_coverpage.md +14 -0
- data/docs/_sidebar.md +14 -0
- data/docs/examples/_sidebar.md +15 -0
- data/docs/examples/data_analysis.md +216 -0
- data/docs/examples/semantic_search_with_llm.md +83 -0
- data/docs/examples/simple-ingest-pipeline.md +326 -0
- data/docs/guides/_sidebar.md +14 -0
- data/docs/guides/aggregations.md +142 -0
- data/docs/guides/machine-learning.md +154 -0
- data/docs/guides/models.md +372 -0
- data/docs/guides/pipelines.md +151 -0
- data/docs/guides/querying.md +361 -0
- data/docs/guides/quick-start.md +72 -0
- data/docs/guides/scopes.md +125 -0
- data/docs/index.html +113 -0
- data/docs/stretchy.cover.png +0 -0
- data/docs/stretchy.logo.png +0 -0
- data/docs/styles.css +90 -0
- data/lib/elasticsearch/api/actions/machine_learning/models/delete_model.rb +33 -0
- data/lib/elasticsearch/api/actions/machine_learning/models/deploy.rb +31 -0
- data/lib/elasticsearch/api/actions/machine_learning/models/get_model.rb +43 -0
- data/lib/elasticsearch/api/actions/machine_learning/models/get_status.rb +31 -0
- data/lib/elasticsearch/api/actions/machine_learning/models/params_registry.rb +45 -0
- data/lib/elasticsearch/api/actions/machine_learning/models/register.rb +45 -0
- data/lib/elasticsearch/api/actions/machine_learning/models/undeploy.rb +32 -0
- data/lib/elasticsearch/api/actions/machine_learning/models/update_model.rb +39 -0
- data/lib/elasticsearch/api/namespace/machine_learning/model.rb +27 -0
- data/lib/opensearch/api/actions/machine_learning/models/delete_model.rb +33 -0
- data/lib/opensearch/api/actions/machine_learning/models/deploy.rb +31 -0
- data/lib/opensearch/api/actions/machine_learning/models/get_model.rb +44 -0
- data/lib/opensearch/api/actions/machine_learning/models/get_status.rb +31 -0
- data/lib/opensearch/api/actions/machine_learning/models/params_registry.rb +45 -0
- data/lib/opensearch/api/actions/machine_learning/models/register.rb +45 -0
- data/lib/opensearch/api/actions/machine_learning/models/undeploy.rb +31 -0
- data/lib/opensearch/api/actions/machine_learning/models/update_model.rb +39 -0
- data/lib/opensearch/api/namespace/machine_learning/model.rb +27 -0
- data/lib/stretchy/attributes/transformers/keyword_transformer.rb +41 -35
- data/lib/stretchy/attributes/type/array.rb +24 -1
- data/lib/stretchy/attributes/type/base.rb +6 -2
- data/lib/stretchy/attributes/type/binary.rb +24 -17
- data/lib/stretchy/attributes/type/boolean.rb +29 -22
- data/lib/stretchy/attributes/type/completion.rb +18 -10
- data/lib/stretchy/attributes/type/constant_keyword.rb +35 -26
- data/lib/stretchy/attributes/type/date_time.rb +81 -20
- data/lib/stretchy/attributes/type/dense_vector.rb +46 -49
- data/lib/stretchy/attributes/type/flattened.rb +28 -19
- data/lib/stretchy/attributes/type/geo_point.rb +21 -12
- data/lib/stretchy/attributes/type/geo_shape.rb +21 -12
- data/lib/stretchy/attributes/type/hash.rb +24 -10
- data/lib/stretchy/attributes/type/histogram.rb +25 -0
- data/lib/stretchy/attributes/type/ip.rb +26 -17
- data/lib/stretchy/attributes/type/join.rb +16 -7
- data/lib/stretchy/attributes/type/keyword.rb +21 -26
- data/lib/stretchy/attributes/type/knn_vector.rb +47 -0
- data/lib/stretchy/attributes/type/match_only_text.rb +22 -1
- data/lib/stretchy/attributes/type/nested.rb +16 -11
- data/lib/stretchy/attributes/type/numeric/base.rb +30 -22
- data/lib/stretchy/attributes/type/numeric/byte.rb +20 -0
- data/lib/stretchy/attributes/type/numeric/double.rb +20 -0
- data/lib/stretchy/attributes/type/numeric/float.rb +20 -0
- data/lib/stretchy/attributes/type/numeric/half_float.rb +20 -0
- data/lib/stretchy/attributes/type/numeric/integer.rb +21 -1
- data/lib/stretchy/attributes/type/numeric/long.rb +20 -0
- data/lib/stretchy/attributes/type/numeric/scaled_float.rb +16 -7
- data/lib/stretchy/attributes/type/numeric/short.rb +20 -0
- data/lib/stretchy/attributes/type/numeric/unsigned_long.rb +21 -1
- data/lib/stretchy/attributes/type/percolator.rb +16 -4
- data/lib/stretchy/attributes/type/point.rb +19 -9
- data/lib/stretchy/attributes/type/range/base.rb +24 -1
- data/lib/stretchy/attributes/type/range/date_range.rb +21 -5
- data/lib/stretchy/attributes/type/range/double_range.rb +20 -4
- data/lib/stretchy/attributes/type/range/float_range.rb +21 -5
- data/lib/stretchy/attributes/type/range/integer_range.rb +20 -4
- data/lib/stretchy/attributes/type/range/ip_range.rb +20 -4
- data/lib/stretchy/attributes/type/range/long_range.rb +20 -4
- data/lib/stretchy/attributes/type/rank_feature.rb +16 -6
- data/lib/stretchy/attributes/type/rank_features.rb +27 -10
- data/lib/stretchy/attributes/type/search_as_you_type.rb +28 -18
- data/lib/stretchy/attributes/type/shape.rb +19 -9
- data/lib/stretchy/attributes/type/sparse_vector.rb +25 -21
- data/lib/stretchy/attributes/type/string.rb +42 -1
- data/lib/stretchy/attributes/type/text.rb +53 -28
- data/lib/stretchy/attributes/type/token_count.rb +21 -11
- data/lib/stretchy/attributes/type/version.rb +16 -6
- data/lib/stretchy/attributes/type/wildcard.rb +36 -25
- data/lib/stretchy/attributes.rb +30 -0
- data/lib/stretchy/delegation/gateway_delegation.rb +86 -2
- data/lib/stretchy/index_setting.rb +94 -0
- data/lib/stretchy/indexing/bulk.rb +75 -3
- data/lib/stretchy/machine_learning/model.rb +192 -0
- data/lib/stretchy/model/callbacks.rb +1 -0
- data/lib/stretchy/model/common.rb +157 -0
- data/lib/stretchy/model/persistence.rb +144 -0
- data/lib/stretchy/model/refreshable.rb +26 -0
- data/lib/stretchy/open_search_compatibility.rb +4 -0
- data/lib/stretchy/pipeline.rb +124 -0
- data/lib/stretchy/pipelines/processor.rb +57 -0
- data/lib/stretchy/querying.rb +7 -7
- data/lib/stretchy/rails/instrumentation/publishers.rb +31 -0
- data/lib/{rails → stretchy/rails}/instrumentation/railtie.rb +11 -6
- data/lib/stretchy/record.rb +5 -4
- data/lib/stretchy/relation.rb +230 -28
- data/lib/stretchy/relations/aggregation_methods/aggregation.rb +59 -0
- data/lib/stretchy/relations/aggregation_methods/avg.rb +45 -0
- data/lib/stretchy/relations/aggregation_methods/bucket_script.rb +47 -0
- data/lib/stretchy/relations/aggregation_methods/bucket_selector.rb +47 -0
- data/lib/stretchy/relations/aggregation_methods/bucket_sort.rb +47 -0
- data/lib/stretchy/relations/aggregation_methods/cardinality.rb +47 -0
- data/lib/stretchy/relations/aggregation_methods/children.rb +47 -0
- data/lib/stretchy/relations/aggregation_methods/composite.rb +41 -0
- data/lib/stretchy/relations/aggregation_methods/date_histogram.rb +53 -0
- data/lib/stretchy/relations/aggregation_methods/date_range.rb +53 -0
- data/lib/stretchy/relations/aggregation_methods/extended_stats.rb +48 -0
- data/lib/stretchy/relations/aggregation_methods/filter.rb +47 -0
- data/lib/stretchy/relations/aggregation_methods/filters.rb +47 -0
- data/lib/stretchy/relations/aggregation_methods/geo_bounds.rb +40 -0
- data/lib/stretchy/relations/aggregation_methods/geo_centroid.rb +40 -0
- data/lib/stretchy/relations/aggregation_methods/global.rb +39 -0
- data/lib/stretchy/relations/aggregation_methods/histogram.rb +43 -0
- data/lib/stretchy/relations/aggregation_methods/ip_range.rb +41 -0
- data/lib/stretchy/relations/aggregation_methods/max.rb +40 -0
- data/lib/stretchy/relations/aggregation_methods/min.rb +41 -0
- data/lib/stretchy/relations/aggregation_methods/missing.rb +40 -0
- data/lib/stretchy/relations/aggregation_methods/nested.rb +40 -0
- data/lib/stretchy/relations/aggregation_methods/percentile_ranks.rb +45 -0
- data/lib/stretchy/relations/aggregation_methods/percentiles.rb +45 -0
- data/lib/stretchy/relations/aggregation_methods/range.rb +42 -0
- data/lib/stretchy/relations/aggregation_methods/reverse_nested.rb +40 -0
- data/lib/stretchy/relations/aggregation_methods/sampler.rb +40 -0
- data/lib/stretchy/relations/aggregation_methods/scripted_metric.rb +43 -0
- data/lib/stretchy/relations/aggregation_methods/significant_terms.rb +45 -0
- data/lib/stretchy/relations/aggregation_methods/stats.rb +42 -0
- data/lib/stretchy/relations/aggregation_methods/sum.rb +42 -0
- data/lib/stretchy/relations/aggregation_methods/terms.rb +46 -0
- data/lib/stretchy/relations/aggregation_methods/top_hits.rb +42 -0
- data/lib/stretchy/relations/aggregation_methods/top_metrics.rb +44 -0
- data/lib/stretchy/relations/aggregation_methods/value_count.rb +41 -0
- data/lib/stretchy/relations/aggregation_methods/weighted_avg.rb +42 -0
- data/lib/stretchy/relations/aggregation_methods.rb +20 -749
- data/lib/stretchy/relations/finder_methods.rb +2 -18
- data/lib/stretchy/relations/null_relation.rb +55 -0
- data/lib/stretchy/relations/query_builder.rb +139 -23
- data/lib/stretchy/relations/query_methods/bind.rb +19 -0
- data/lib/stretchy/relations/query_methods/extending.rb +29 -0
- data/lib/stretchy/relations/query_methods/fields.rb +70 -0
- data/lib/stretchy/relations/query_methods/filter_query.rb +53 -0
- data/lib/stretchy/relations/query_methods/has_field.rb +40 -0
- data/lib/stretchy/relations/query_methods/highlight.rb +75 -0
- data/lib/stretchy/relations/query_methods/hybrid.rb +60 -0
- data/lib/stretchy/relations/query_methods/ids.rb +40 -0
- data/lib/stretchy/relations/query_methods/match.rb +52 -0
- data/lib/stretchy/relations/query_methods/must_not.rb +54 -0
- data/lib/stretchy/relations/query_methods/neural.rb +58 -0
- data/lib/stretchy/relations/query_methods/neural_sparse.rb +43 -0
- data/lib/stretchy/relations/query_methods/none.rb +21 -0
- data/lib/stretchy/relations/query_methods/or_filter.rb +21 -0
- data/lib/stretchy/relations/query_methods/order.rb +63 -0
- data/lib/stretchy/relations/query_methods/query_string.rb +44 -0
- data/lib/stretchy/relations/query_methods/regexp.rb +61 -0
- data/lib/stretchy/relations/query_methods/should.rb +51 -0
- data/lib/stretchy/relations/query_methods/size.rb +44 -0
- data/lib/stretchy/relations/query_methods/skip_callbacks.rb +47 -0
- data/lib/stretchy/relations/query_methods/source.rb +59 -0
- data/lib/stretchy/relations/query_methods/where.rb +113 -0
- data/lib/stretchy/relations/query_methods.rb +51 -540
- data/lib/stretchy/relations/scoping/default.rb +136 -0
- data/lib/stretchy/relations/scoping/named.rb +70 -0
- data/lib/stretchy/relations/scoping/scope_registry.rb +36 -0
- data/lib/stretchy/relations/scoping.rb +30 -0
- data/lib/stretchy/relations/search_option_methods.rb +2 -0
- data/lib/stretchy/shared_scopes.rb +6 -1
- data/lib/stretchy/version.rb +1 -1
- data/lib/stretchy.rb +23 -11
- metadata +147 -18
- data/lib/rails/instrumentation/publishers.rb +0 -29
- data/lib/stretchy/common.rb +0 -33
- data/lib/stretchy/null_relation.rb +0 -53
- data/lib/stretchy/persistence.rb +0 -43
- data/lib/stretchy/refreshable.rb +0 -15
- data/lib/stretchy/scoping/default.rb +0 -134
- data/lib/stretchy/scoping/named.rb +0 -68
- data/lib/stretchy/scoping/scope_registry.rb +0 -34
- data/lib/stretchy/scoping.rb +0 -28
@@ -3,6 +3,8 @@ module Stretchy
|
|
3
3
|
|
4
4
|
module FinderMethods
|
5
5
|
|
6
|
+
METHODS = [:first, :first!, :last, :last!]
|
7
|
+
|
6
8
|
def first
|
7
9
|
return results.first if @loaded
|
8
10
|
spawn.first!.results.first
|
@@ -39,24 +41,6 @@ module Stretchy
|
|
39
41
|
self
|
40
42
|
end
|
41
43
|
|
42
|
-
# size is not permitted to the count API but queries are.
|
43
|
-
#
|
44
|
-
# if a query is supplied with `.count` then the user wants a count of the results
|
45
|
-
# matching the query
|
46
|
-
#
|
47
|
-
# however, the default_size is used to limit the number of results returned
|
48
|
-
# so we remove the size from the query and then call `.count` API
|
49
|
-
#
|
50
|
-
# but if the user supplies a limit, then we should assume they want a count of the results
|
51
|
-
# which could lead to some confusion
|
52
|
-
# suppose the user calls `.size(100).count` and the default_size is 100
|
53
|
-
# if we remove size from the query, then the count could be greater than 100
|
54
|
-
#
|
55
|
-
# I think the best way to handle this is to remove the size from the query only if it was
|
56
|
-
# applied by the default_size
|
57
|
-
# If the user supplies a limit, then we should assume they want a count of the results
|
58
|
-
#
|
59
|
-
# if size is called with a limit,
|
60
44
|
def count
|
61
45
|
return results.count if @loaded || @values[:size].present?
|
62
46
|
spawn.count!
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Stretchy
|
4
|
+
module Relations
|
5
|
+
module NullRelation # :nodoc:
|
6
|
+
def pluck(*column_names)
|
7
|
+
[]
|
8
|
+
end
|
9
|
+
|
10
|
+
def delete_all
|
11
|
+
0
|
12
|
+
end
|
13
|
+
|
14
|
+
def update_all(_updates)
|
15
|
+
0
|
16
|
+
end
|
17
|
+
|
18
|
+
def delete(_id_or_array)
|
19
|
+
0
|
20
|
+
end
|
21
|
+
|
22
|
+
def empty?
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
def none?
|
27
|
+
true
|
28
|
+
end
|
29
|
+
|
30
|
+
def any?
|
31
|
+
false
|
32
|
+
end
|
33
|
+
|
34
|
+
def one?
|
35
|
+
false
|
36
|
+
end
|
37
|
+
|
38
|
+
def many?
|
39
|
+
false
|
40
|
+
end
|
41
|
+
|
42
|
+
def exists?(_conditions = :none)
|
43
|
+
false
|
44
|
+
end
|
45
|
+
|
46
|
+
def or(other)
|
47
|
+
other.spawn
|
48
|
+
end
|
49
|
+
|
50
|
+
def exec_queries
|
51
|
+
@records = OpenStruct.new(klass: NullRelation, total: 0, results: []).freeze
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -27,10 +27,26 @@ module Stretchy
|
|
27
27
|
@query ||= compact_where(values[:where])
|
28
28
|
end
|
29
29
|
|
30
|
+
def match_query
|
31
|
+
@match_query ||= values[:match]
|
32
|
+
end
|
33
|
+
|
30
34
|
def query_strings
|
31
35
|
@query_string ||= compact_where(values[:query_string], bool: false)
|
32
36
|
end
|
33
37
|
|
38
|
+
def neural_sparse
|
39
|
+
@neural_sparse ||= values[:neural_sparse]
|
40
|
+
end
|
41
|
+
|
42
|
+
def neural
|
43
|
+
@neural ||= values[:neural]
|
44
|
+
end
|
45
|
+
|
46
|
+
def hybrid
|
47
|
+
@hybrid ||= values[:hybrid]
|
48
|
+
end
|
49
|
+
|
34
50
|
def must_nots
|
35
51
|
@must_nots ||= compact_where(values[:must_not])
|
36
52
|
end
|
@@ -39,12 +55,16 @@ module Stretchy
|
|
39
55
|
@shoulds ||= compact_where(values[:should])
|
40
56
|
end
|
41
57
|
|
58
|
+
def ids
|
59
|
+
@ids ||= values[:ids]
|
60
|
+
end
|
61
|
+
|
42
62
|
def regexes
|
43
63
|
@regexes ||= values[:regexp]
|
44
64
|
end
|
45
65
|
|
46
66
|
def fields
|
47
|
-
values[:
|
67
|
+
values[:fields]
|
48
68
|
end
|
49
69
|
|
50
70
|
def source
|
@@ -86,14 +106,14 @@ module Stretchy
|
|
86
106
|
build_highlights unless highlights.blank?
|
87
107
|
build_fields unless fields.blank?
|
88
108
|
build_source unless source.blank?
|
89
|
-
build_aggregations unless aggregations.blank?
|
109
|
+
build_aggregations(aggregations, structure) unless aggregations.blank?
|
90
110
|
structure.attributes!.with_indifferent_access
|
91
111
|
end
|
92
112
|
|
93
113
|
private
|
94
114
|
|
95
115
|
def missing_bool_query?
|
96
|
-
query.
|
116
|
+
query.blank? && must_nots.nil? && shoulds.nil? && regexes.nil?
|
97
117
|
end
|
98
118
|
|
99
119
|
def missing_query_string?
|
@@ -104,12 +124,80 @@ module Stretchy
|
|
104
124
|
query_filters.nil? && or_filters.nil?
|
105
125
|
end
|
106
126
|
|
127
|
+
def missing_neural?
|
128
|
+
neural_sparse.nil? && neural.nil? && hybrid.nil?
|
129
|
+
end
|
130
|
+
|
131
|
+
def no_query?
|
132
|
+
missing_bool_query? && missing_query_string? && missing_query_filter? && missing_neural? && ids.nil? && match_query.nil?
|
133
|
+
end
|
134
|
+
|
107
135
|
def build_query
|
108
|
-
return if
|
136
|
+
return if no_query?
|
109
137
|
structure.query do
|
138
|
+
structure.ids do
|
139
|
+
structure.values ids.flatten.compact.uniq
|
140
|
+
end unless ids.nil?
|
141
|
+
|
142
|
+
structure.match do
|
143
|
+
mq = match_query.dup
|
144
|
+
field, value = mq.first.shift
|
145
|
+
structure.set! field do
|
146
|
+
structure.query value
|
147
|
+
structure.extract! mq.last, *mq.last.keys
|
148
|
+
end
|
149
|
+
end unless match_query.nil?
|
150
|
+
|
151
|
+
structure.hybrid do
|
152
|
+
structure.queries do
|
153
|
+
structure.child! do
|
154
|
+
params = hybrid[:neural].dup
|
155
|
+
field_name, query_text = params.shift
|
156
|
+
structure.neural do
|
157
|
+
structure.set! field_name do
|
158
|
+
structure.query_text query_text
|
159
|
+
structure.extract! params, *params.keys
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
structure.child! do
|
165
|
+
hybrid_query = hybrid[:query].dup
|
166
|
+
structure.extract! hybrid_query, *hybrid_query.keys
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
end unless hybrid.nil?
|
171
|
+
|
172
|
+
structure.neural_sparse do
|
173
|
+
neural_sparse.each do |args|
|
174
|
+
params = args.dup
|
175
|
+
field_name, query_text = params.shift
|
176
|
+
structure.set! field_name do
|
177
|
+
structure.query_text query_text
|
178
|
+
structure.extract! params, *params.keys
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end unless neural_sparse.blank?
|
182
|
+
|
183
|
+
structure.neural do
|
184
|
+
neural.each do |args|
|
185
|
+
params = args.dup
|
186
|
+
field_name, query = params.shift
|
187
|
+
structure.set! field_name do
|
188
|
+
if query.is_a?(Hash)
|
189
|
+
structure.extract! query, *query.keys
|
190
|
+
else
|
191
|
+
structure.query_text query
|
192
|
+
end
|
193
|
+
structure.extract! params, *params.keys
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end unless neural.blank?
|
197
|
+
|
110
198
|
structure.regexp do
|
111
|
-
build_regexp
|
112
|
-
end
|
199
|
+
build_regexp
|
200
|
+
end unless regexes.nil?
|
113
201
|
|
114
202
|
structure.bool do
|
115
203
|
|
@@ -121,18 +209,17 @@ module Stretchy
|
|
121
209
|
|
122
210
|
end unless missing_bool_query? && missing_query_filter?
|
123
211
|
|
124
|
-
|
125
|
-
|
126
212
|
structure.query_string do
|
127
213
|
structure.extract! query_string_options, *query_string_options.keys
|
128
214
|
structure.query query_strings
|
129
215
|
end unless query_strings.nil?
|
216
|
+
|
130
217
|
end.with_indifferent_access
|
131
218
|
end
|
132
219
|
|
133
220
|
def build_regexp
|
134
221
|
regexes.each do |args|
|
135
|
-
target_field = args.first.keys.first
|
222
|
+
target_field = keyword_transformer.transform(args.first.keys.first.to_s)
|
136
223
|
value_field = args.first.values.first
|
137
224
|
structure.set! target_field, args.last.merge(value: value_field)
|
138
225
|
end
|
@@ -187,10 +274,10 @@ module Stretchy
|
|
187
274
|
end
|
188
275
|
end
|
189
276
|
|
190
|
-
def build_aggregations
|
191
|
-
|
192
|
-
|
193
|
-
|
277
|
+
def build_aggregations(aggregation_args, aggregation_structure)
|
278
|
+
aggregation_structure.aggregations do
|
279
|
+
aggregation_args.each do |agg|
|
280
|
+
aggregation_structure.set! agg[:name], aggregation(agg[:name], keyword_transformer.transform(agg[:args], :aggs, :aggregations))
|
194
281
|
end
|
195
282
|
end
|
196
283
|
end
|
@@ -210,7 +297,7 @@ module Stretchy
|
|
210
297
|
|
211
298
|
def extra_search_options
|
212
299
|
unless self.count?
|
213
|
-
values[:size] = size.present? ? size :
|
300
|
+
values[:size] = size.present? ? size : default_size
|
214
301
|
else
|
215
302
|
values[:size] = nil
|
216
303
|
end
|
@@ -220,7 +307,7 @@ module Stretchy
|
|
220
307
|
def compact_where(q, opts = {bool:true})
|
221
308
|
return if q.nil?
|
222
309
|
if opts.delete(:bool)
|
223
|
-
as_must(q)
|
310
|
+
as_must([merge_and_append(q)])
|
224
311
|
else
|
225
312
|
as_query_string(q.flatten)
|
226
313
|
end
|
@@ -231,10 +318,16 @@ module Stretchy
|
|
231
318
|
q.each do |arg|
|
232
319
|
case arg
|
233
320
|
when Hash
|
234
|
-
arg = keyword_transformer.transform(arg)
|
321
|
+
arg = keyword_transformer.transform(arg, :match)
|
235
322
|
arg.each_pair do |k,v|
|
236
|
-
|
237
|
-
|
323
|
+
if k == :match
|
324
|
+
v.each do |field, value|
|
325
|
+
_must << (field.is_a?(Hash) ? { k => field} : { k => {field => value}})
|
326
|
+
end
|
327
|
+
else
|
328
|
+
# If v is an array, we build a terms query otherwise a term query
|
329
|
+
_must << (v.is_a?(Array) ? {terms: Hash[k,v]} : {term: Hash[k,v]})
|
330
|
+
end
|
238
331
|
end
|
239
332
|
when String
|
240
333
|
_must << {term: Hash[[arg.split(/:/).collect(&:strip)]]}
|
@@ -253,12 +346,30 @@ module Stretchy
|
|
253
346
|
|
254
347
|
q.each do |arg|
|
255
348
|
arg.each_pair { |k,v| _and << "(#{k}:#{v})" } if arg.class == Hash
|
256
|
-
|
349
|
+
if q.length == 1
|
350
|
+
_and << "#{arg}" if arg.class == String
|
351
|
+
else
|
352
|
+
_and << "(#{arg})" if arg.class == String
|
353
|
+
end
|
257
354
|
end
|
258
355
|
_and.join(" AND ")
|
259
356
|
end
|
260
357
|
|
261
|
-
|
358
|
+
def merge_and_append(queries)
|
359
|
+
result = {}
|
360
|
+
queries.each do |hash|
|
361
|
+
hash.each do |key, value|
|
362
|
+
if result[key].is_a?(Array)
|
363
|
+
result[key] << value
|
364
|
+
elsif result.key?(key)
|
365
|
+
result[key] = [result[key], value]
|
366
|
+
else
|
367
|
+
result[key] = value
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
result
|
372
|
+
end
|
262
373
|
|
263
374
|
def extract_highlighter(highlighter)
|
264
375
|
Jbuilder.new do |highlight|
|
@@ -280,12 +391,17 @@ module Stretchy
|
|
280
391
|
end
|
281
392
|
|
282
393
|
def aggregation(name, opts = {})
|
283
|
-
Jbuilder.new do |
|
394
|
+
Jbuilder.new do |agg_structure|
|
284
395
|
case
|
285
396
|
when opts.is_a?(Hash)
|
286
|
-
|
397
|
+
nested_agg = opts.delete(:aggs) || opts.delete(:aggregations)
|
398
|
+
|
399
|
+
agg_structure.extract! opts, *opts.keys
|
400
|
+
|
401
|
+
build_aggregations(nested_agg.map {|d| {:name => d.first, :args => d.last } }, agg_structure) if nested_agg
|
402
|
+
|
287
403
|
when opts.is_a?(Array)
|
288
|
-
extract_filter_arguments_from_array(
|
404
|
+
extract_filter_arguments_from_array(agg_structure, opts)
|
289
405
|
else
|
290
406
|
raise "#aggregation only accepts Hash or Array"
|
291
407
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Stretchy
|
2
|
+
module Relations
|
3
|
+
module QueryMethods
|
4
|
+
module Bind
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
def bind(value)
|
7
|
+
spawn.bind!(value)
|
8
|
+
end
|
9
|
+
|
10
|
+
def bind!(value) # :nodoc:
|
11
|
+
self.bind_values += [value]
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
QueryMethods.register!(:bind)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Stretchy
|
2
|
+
module Relations
|
3
|
+
module QueryMethods
|
4
|
+
module Extending
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
def extending(*modules, &block)
|
7
|
+
if modules.any? || block
|
8
|
+
spawn.extending!(*modules, &block)
|
9
|
+
else
|
10
|
+
self
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def extending!(*modules, &block) # :nodoc:
|
15
|
+
modules << Module.new(&block) if block
|
16
|
+
modules.flatten!
|
17
|
+
|
18
|
+
self.extending_values += modules
|
19
|
+
extend(*extending_values) if extending_values.any?
|
20
|
+
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
QueryMethods.register!(:extending)
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Stretchy
|
2
|
+
module Relations
|
3
|
+
module QueryMethods
|
4
|
+
module Fields
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
# Specify the fields to be returned by the Elasticsearch query.
|
8
|
+
#
|
9
|
+
# This method accepts a variable number of arguments, each of which is the name of a field to be returned.
|
10
|
+
# If no arguments are provided, all fields are returned.
|
11
|
+
#
|
12
|
+
# To retrieve specific fields in the search response, use the fields parameter.
|
13
|
+
# Because it consults the index mappings, the fields parameter provides several advantages over referencing
|
14
|
+
# the `_source` directly. Specifically, the fields parameter:
|
15
|
+
# Returns each value in a standardized way that matches its mapping type
|
16
|
+
# Accepts multi-fields and field aliases
|
17
|
+
# Formats dates and spatial data types
|
18
|
+
# Retrieves runtime field values
|
19
|
+
# Returns fields calculated by a script at index time
|
20
|
+
# Returns fields from related indices using lookup runtime fields
|
21
|
+
#
|
22
|
+
# ### Parameters
|
23
|
+
# - `args:` The Array of field names to be returned by the query (default: []).
|
24
|
+
#
|
25
|
+
# ### Returns
|
26
|
+
# Returns a new Stretchy::Relation with the specified fields to be returned.
|
27
|
+
#
|
28
|
+
# ---
|
29
|
+
#
|
30
|
+
# ### Examples
|
31
|
+
#
|
32
|
+
# #### Single field
|
33
|
+
# ```ruby
|
34
|
+
# Model.fields(:title)
|
35
|
+
# ```
|
36
|
+
#
|
37
|
+
# #### Multiple fields
|
38
|
+
# ```ruby
|
39
|
+
# Model.fields(:title, :author)
|
40
|
+
# ```
|
41
|
+
#
|
42
|
+
# #### Nested fields
|
43
|
+
# ```ruby
|
44
|
+
# Model.fields('author.name', 'author.age')
|
45
|
+
# ```
|
46
|
+
#
|
47
|
+
# #### Wildcard
|
48
|
+
# ```ruby
|
49
|
+
# Model.fields('books.*')
|
50
|
+
# ```
|
51
|
+
#
|
52
|
+
def fields(*args)
|
53
|
+
spawn.field!(*args)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Alias for {#field}
|
57
|
+
# @see #field
|
58
|
+
alias :field :fields
|
59
|
+
|
60
|
+
def field!(*args) # :nodoc:
|
61
|
+
self.fields_values += args
|
62
|
+
self
|
63
|
+
end
|
64
|
+
|
65
|
+
QueryMethods.register!(:field, :fields)
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Stretchy
|
2
|
+
module Relations
|
3
|
+
module QueryMethods
|
4
|
+
module FilterQuery
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
# Adds a filter to the Elasticsearch query.
|
8
|
+
#
|
9
|
+
# This method is used to filter the results of a query without affecting the score. It accepts a type and a condition.
|
10
|
+
# The type can be any valid Elasticsearch filter type, such as `:term`, `:range`, or `:bool`. The condition is a hash
|
11
|
+
# that specifies the filter conditions.
|
12
|
+
#
|
13
|
+
# ### Parameters
|
14
|
+
# - `type:` The Symbol representing the filter type.
|
15
|
+
# - `condition:` The Hash containing the filter conditions.
|
16
|
+
#
|
17
|
+
# ### Returns
|
18
|
+
# Returns a new Stretchy::Relation with the specified filter applied.
|
19
|
+
#
|
20
|
+
# ---
|
21
|
+
#
|
22
|
+
# ### Examples
|
23
|
+
#
|
24
|
+
# #### Term filter
|
25
|
+
# ```ruby
|
26
|
+
# Model.filter_query(:term, color: 'blue')
|
27
|
+
# ```
|
28
|
+
#
|
29
|
+
# #### Range filter
|
30
|
+
# ```ruby
|
31
|
+
# Model.filter_query(:range, age: { gte: 21 })
|
32
|
+
# ```
|
33
|
+
#
|
34
|
+
# #### Bool filter
|
35
|
+
# ```ruby
|
36
|
+
# Model.filter_query(:bool, must: [{ term: { color: 'blue' } }, { range: { age: { gte: 21 } } }])
|
37
|
+
# ```
|
38
|
+
#
|
39
|
+
def filter_query(name, options = {}, &block)
|
40
|
+
spawn.filter_query!(name, options, &block)
|
41
|
+
end
|
42
|
+
|
43
|
+
def filter_query!(name, options = {}, &block) # :nodoc:
|
44
|
+
self.filter_query_values += [{name: name, args: options}]
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
QueryMethods.register!(:filter_query)
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Stretchy
|
2
|
+
module Relations
|
3
|
+
module QueryMethods
|
4
|
+
module HasField
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
# Checks if a field exists in the Elasticsearch document.
|
8
|
+
#
|
9
|
+
# This method is used to filter the results of a query based on whether a field exists or not in the document.
|
10
|
+
# It accepts a field name as an argument and adds an `exists` filter to the query.
|
11
|
+
#
|
12
|
+
# ### Parameters
|
13
|
+
# - `field:` The Symbol or String representing the field name.
|
14
|
+
#
|
15
|
+
# ### Returns
|
16
|
+
# Returns a new Stretchy::Relation with the `exists` filter applied.
|
17
|
+
#
|
18
|
+
# ---
|
19
|
+
#
|
20
|
+
# ### Examples
|
21
|
+
#
|
22
|
+
# #### Has field
|
23
|
+
# ```ruby
|
24
|
+
# Model.has_field(:title)
|
25
|
+
# ```
|
26
|
+
#
|
27
|
+
# #### Nested field exists
|
28
|
+
# ```ruby
|
29
|
+
# Model.has_field('author.name')
|
30
|
+
# ```
|
31
|
+
#
|
32
|
+
def has_field(field)
|
33
|
+
spawn.filter_query(:exists, {field: field})
|
34
|
+
end
|
35
|
+
|
36
|
+
QueryMethods.register!(:has_field)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Stretchy
|
2
|
+
module Relations
|
3
|
+
module QueryMethods
|
4
|
+
module Highlight
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
# Highlights search results on one or more fields.
|
7
|
+
#
|
8
|
+
# This method is used to highlight search results on one or more fields. The fields that match the user query get
|
9
|
+
# highlighted. It accepts a variable number of arguments, each of which is the name of a field to be highlighted.
|
10
|
+
#
|
11
|
+
# ### Parameters
|
12
|
+
#
|
13
|
+
# - `field:` The Symbol of a field name to be highlighted by the query or a series of keyword hashes with the field name as the key and the highlight options as the value
|
14
|
+
# - `options:` The Hash of highlight options
|
15
|
+
# - `boundary_chars:` The String of the boundary characters (default: ".,!? \t\n")
|
16
|
+
# - `boundary_max_scan:` The Integer of the maximum number of characters to scan to find the boundary characters (default: 20)
|
17
|
+
# - `boundary_scanner:` The String of the boundary scanner type (default: "sentence")
|
18
|
+
# - "sentence" Breaks text into sentences
|
19
|
+
# - "word" Breaks text into words
|
20
|
+
# - "char" Breaks text into characters
|
21
|
+
# - `boundary_scanner_locale:` The String of the locale for the boundary scanner (default: "en-US")
|
22
|
+
# - `encoder:` The String of the encoder type (default: "default").
|
23
|
+
# - `fragmenter:` The String of the fragmenter type (default: "simple").
|
24
|
+
# - `force_source:` The Boolean to force highlighting on the source (default: false).
|
25
|
+
# - `fragment_offset:` The Integer of the number of characters to offset the fragment (default: 0).
|
26
|
+
# - `fragment_size:` The Integer of the number of characters in a fragment (default: 100).
|
27
|
+
# - `highlight_query:` The Hash of highlight query options (default: {}).
|
28
|
+
# - `matched_fields:` The Array of fields to be highlighted (default: []).
|
29
|
+
# - `no_match_size:` The Integer of the number of characters to return if no matches are found (default: 150).
|
30
|
+
# - `number_of_fragments:` The Integer of the number of fragments to return (default: 5).
|
31
|
+
# - `order:` The String of the order of the highlighted fragments (default: "score").
|
32
|
+
# - `phrase_limit:` The Integer of the maximum number of phrases to highlight (default: 256).
|
33
|
+
# - `pre_tags:` The String or Array of Strings to be used as the pre-highlight tags (default: "<em>").
|
34
|
+
# - `post_tags:` The String or Array of Strings to be used as the post-highlight tags (default: "</em>").
|
35
|
+
# - `require_field_match:` The Boolean to require field matching (default: true).
|
36
|
+
# - `max_analyzed_offset:` The Integer of the maximum number of characters to analyze (default: 1000000).
|
37
|
+
# - `tags_schema:` The String of the tags schema (default: "styled").
|
38
|
+
# - `type:` The String of the highlight type (default: "unified").
|
39
|
+
# * "unified" - Highlights fields based on the Unified Highlighter.
|
40
|
+
# * "plain" - Highlights fields based on the Plain Highlighter.
|
41
|
+
# * "fvh" - Highlights fields based on the Fast Vector Highlighter.
|
42
|
+
#
|
43
|
+
# ### Returns
|
44
|
+
# Returns a new Stretchy::Relation with the specified fields to be highlighted.
|
45
|
+
#
|
46
|
+
# ---
|
47
|
+
#
|
48
|
+
# ### Examples
|
49
|
+
#
|
50
|
+
# #### Single field
|
51
|
+
#
|
52
|
+
# ```
|
53
|
+
# Model.query_string("body:Cat OR Lion").highlight(:body)
|
54
|
+
# ```
|
55
|
+
#
|
56
|
+
# ### Custom highlight options
|
57
|
+
#
|
58
|
+
# ```ruby
|
59
|
+
# Model.query_string("name: Soph*").highlight(name: {pre_tags: "__", post_tags: "__"})
|
60
|
+
# ```
|
61
|
+
#
|
62
|
+
def highlight(*args)
|
63
|
+
spawn.highlight!(*args)
|
64
|
+
end
|
65
|
+
|
66
|
+
def highlight!(*args) # :nodoc:
|
67
|
+
self.highlight_values += args
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
QueryMethods.register!(:highlight)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|