stretchy-model 0.6.5 → 0.7.0
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/docs/.nojekyll +0 -0
- data/docs/README.md +147 -0
- data/docs/_coverpage.md +14 -0
- data/docs/_sidebar.md +15 -0
- data/docs/examples/_sidebar.md +15 -0
- data/docs/examples/data_analysis.md +216 -0
- data/docs/examples/neural_search_with_llm.md +381 -0
- data/docs/examples/simple-ingest-pipeline.md +326 -0
- data/docs/guides/_sidebar.md +15 -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/connector/check_in.rb +64 -0
- data/lib/elasticsearch/api/actions/connector/delete.rb +64 -0
- data/lib/elasticsearch/api/actions/connector/get.rb +64 -0
- data/lib/elasticsearch/api/actions/connector/last_sync.rb +66 -0
- data/lib/elasticsearch/api/actions/connector/list.rb +60 -0
- data/lib/elasticsearch/api/actions/connector/post.rb +57 -0
- data/lib/elasticsearch/api/actions/connector/put.rb +66 -0
- data/lib/elasticsearch/api/actions/connector/update_api_key_id.rb +66 -0
- data/lib/elasticsearch/api/actions/connector/update_configuration.rb +66 -0
- data/lib/elasticsearch/api/actions/connector/update_error.rb +66 -0
- data/lib/elasticsearch/api/actions/connector/update_filtering.rb +66 -0
- data/lib/elasticsearch/api/actions/connector/update_index_name.rb +66 -0
- data/lib/elasticsearch/api/actions/connector/update_name.rb +66 -0
- data/lib/elasticsearch/api/actions/connector/update_native.rb +66 -0
- data/lib/elasticsearch/api/actions/connector/update_pipeline.rb +66 -0
- data/lib/elasticsearch/api/actions/connector/update_scheduling.rb +66 -0
- data/lib/elasticsearch/api/actions/connector/update_service_type.rb +66 -0
- data/lib/elasticsearch/api/actions/connector/update_status.rb +66 -0
- data/lib/elasticsearch/api/namespace/connector.rb +36 -0
- data/lib/opensearch/api/actions/machine_learning/connector/delete.rb +42 -0
- data/lib/opensearch/api/actions/machine_learning/connector/get.rb +42 -0
- data/lib/opensearch/api/actions/machine_learning/connector/list.rb +38 -0
- data/lib/opensearch/api/actions/machine_learning/connector/post.rb +35 -0
- data/lib/opensearch/api/actions/machine_learning/connector/put.rb +44 -0
- data/lib/opensearch/api/actions/machine_learning/models/predict.rb +32 -0
- data/lib/opensearch/api/namespace/connector.rb +19 -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 +28 -17
- 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 +16 -9
- 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 +29 -0
- data/lib/stretchy/delegation/gateway_delegation.rb +78 -0
- data/lib/stretchy/index_setting.rb +94 -0
- data/lib/stretchy/indexing/bulk.rb +75 -3
- data/lib/stretchy/machine_learning/connector.rb +130 -0
- data/lib/stretchy/machine_learning/errors.rb +25 -0
- data/lib/stretchy/machine_learning/model.rb +162 -109
- data/lib/stretchy/machine_learning/registry.rb +19 -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 +2 -0
- data/lib/stretchy/pipeline.rb +2 -1
- data/lib/stretchy/pipelines/processor.rb +40 -36
- data/lib/stretchy/querying.rb +7 -8
- data/lib/stretchy/rails/railtie.rb +11 -0
- data/lib/stretchy/rails/tasks/connector/create.rake +32 -0
- data/lib/stretchy/rails/tasks/connector/delete.rake +27 -0
- data/lib/stretchy/rails/tasks/connector/status.rake +31 -0
- data/lib/stretchy/rails/tasks/connector/update.rake +32 -0
- data/lib/stretchy/rails/tasks/index/create.rake +28 -0
- data/lib/stretchy/rails/tasks/index/delete.rake +27 -0
- data/lib/stretchy/rails/tasks/index/status.rake +23 -0
- data/lib/stretchy/rails/tasks/ml/delete.rake +25 -0
- data/lib/stretchy/rails/tasks/ml/deploy.rake +78 -0
- data/lib/stretchy/rails/tasks/ml/status.rake +31 -0
- data/lib/stretchy/rails/tasks/pipeline/create.rake +27 -0
- data/lib/stretchy/rails/tasks/pipeline/delete.rake +26 -0
- data/lib/stretchy/rails/tasks/pipeline/status.rake +25 -0
- data/lib/stretchy/rails/tasks/status.rake +15 -0
- data/lib/stretchy/rails/tasks/stretchy.rake +42 -0
- data/lib/stretchy/record.rb +5 -4
- data/lib/stretchy/relation.rb +229 -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 +82 -36
- 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 +48 -569
- 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/version.rb +1 -1
- data/lib/stretchy.rb +24 -10
- metadata +170 -17
- data/lib/stretchy/common.rb +0 -38
- 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,6 +27,10 @@ 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
|
@@ -51,12 +55,16 @@ module Stretchy
|
|
51
55
|
@shoulds ||= compact_where(values[:should])
|
52
56
|
end
|
53
57
|
|
58
|
+
def ids
|
59
|
+
@ids ||= values[:ids]
|
60
|
+
end
|
61
|
+
|
54
62
|
def regexes
|
55
63
|
@regexes ||= values[:regexp]
|
56
64
|
end
|
57
65
|
|
58
66
|
def fields
|
59
|
-
values[:
|
67
|
+
values[:fields]
|
60
68
|
end
|
61
69
|
|
62
70
|
def source
|
@@ -98,14 +106,14 @@ module Stretchy
|
|
98
106
|
build_highlights unless highlights.blank?
|
99
107
|
build_fields unless fields.blank?
|
100
108
|
build_source unless source.blank?
|
101
|
-
build_aggregations unless aggregations.blank?
|
109
|
+
build_aggregations(aggregations, structure) unless aggregations.blank?
|
102
110
|
structure.attributes!.with_indifferent_access
|
103
111
|
end
|
104
112
|
|
105
113
|
private
|
106
114
|
|
107
115
|
def missing_bool_query?
|
108
|
-
query.
|
116
|
+
query.blank? && must_nots.nil? && shoulds.nil? && regexes.nil?
|
109
117
|
end
|
110
118
|
|
111
119
|
def missing_query_string?
|
@@ -121,33 +129,42 @@ module Stretchy
|
|
121
129
|
end
|
122
130
|
|
123
131
|
def no_query?
|
124
|
-
missing_bool_query? && missing_query_string? && missing_query_filter? && missing_neural?
|
132
|
+
missing_bool_query? && missing_query_string? && missing_query_filter? && missing_neural? && ids.nil? && match_query.nil?
|
125
133
|
end
|
126
134
|
|
127
135
|
def build_query
|
128
136
|
return if no_query?
|
129
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?
|
130
150
|
|
131
151
|
structure.hybrid do
|
132
152
|
structure.queries do
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
structure.extract! params, *params.keys
|
141
|
-
end
|
142
|
-
end
|
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
|
143
160
|
end
|
144
161
|
end
|
162
|
+
end
|
145
163
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
end
|
164
|
+
structure.child! do
|
165
|
+
hybrid_query = hybrid[:query].dup
|
166
|
+
structure.extract! hybrid_query, *hybrid_query.keys
|
167
|
+
end
|
151
168
|
|
152
169
|
end
|
153
170
|
end unless hybrid.nil?
|
@@ -179,8 +196,8 @@ module Stretchy
|
|
179
196
|
end unless neural.blank?
|
180
197
|
|
181
198
|
structure.regexp do
|
182
|
-
build_regexp
|
183
|
-
end
|
199
|
+
build_regexp
|
200
|
+
end unless regexes.nil?
|
184
201
|
|
185
202
|
structure.bool do
|
186
203
|
|
@@ -202,7 +219,7 @@ module Stretchy
|
|
202
219
|
|
203
220
|
def build_regexp
|
204
221
|
regexes.each do |args|
|
205
|
-
target_field = args.first.keys.first
|
222
|
+
target_field = keyword_transformer.transform(args.first.keys.first.to_s)
|
206
223
|
value_field = args.first.values.first
|
207
224
|
structure.set! target_field, args.last.merge(value: value_field)
|
208
225
|
end
|
@@ -257,10 +274,10 @@ module Stretchy
|
|
257
274
|
end
|
258
275
|
end
|
259
276
|
|
260
|
-
def build_aggregations
|
261
|
-
|
262
|
-
|
263
|
-
|
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))
|
264
281
|
end
|
265
282
|
end
|
266
283
|
end
|
@@ -280,7 +297,7 @@ module Stretchy
|
|
280
297
|
|
281
298
|
def extra_search_options
|
282
299
|
unless self.count?
|
283
|
-
values[:size] = size.present? ? size :
|
300
|
+
values[:size] = size.present? ? size : default_size
|
284
301
|
else
|
285
302
|
values[:size] = nil
|
286
303
|
end
|
@@ -290,7 +307,7 @@ module Stretchy
|
|
290
307
|
def compact_where(q, opts = {bool:true})
|
291
308
|
return if q.nil?
|
292
309
|
if opts.delete(:bool)
|
293
|
-
as_must(q)
|
310
|
+
as_must([merge_and_append(q)])
|
294
311
|
else
|
295
312
|
as_query_string(q.flatten)
|
296
313
|
end
|
@@ -301,10 +318,16 @@ module Stretchy
|
|
301
318
|
q.each do |arg|
|
302
319
|
case arg
|
303
320
|
when Hash
|
304
|
-
arg = keyword_transformer.transform(arg)
|
321
|
+
arg = keyword_transformer.transform(arg, :match)
|
305
322
|
arg.each_pair do |k,v|
|
306
|
-
|
307
|
-
|
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
|
308
331
|
end
|
309
332
|
when String
|
310
333
|
_must << {term: Hash[[arg.split(/:/).collect(&:strip)]]}
|
@@ -323,12 +346,30 @@ module Stretchy
|
|
323
346
|
|
324
347
|
q.each do |arg|
|
325
348
|
arg.each_pair { |k,v| _and << "(#{k}:#{v})" } if arg.class == Hash
|
326
|
-
|
349
|
+
if q.length == 1
|
350
|
+
_and << "#{arg}" if arg.class == String
|
351
|
+
else
|
352
|
+
_and << "(#{arg})" if arg.class == String
|
353
|
+
end
|
327
354
|
end
|
328
355
|
_and.join(" AND ")
|
329
356
|
end
|
330
357
|
|
331
|
-
|
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
|
332
373
|
|
333
374
|
def extract_highlighter(highlighter)
|
334
375
|
Jbuilder.new do |highlight|
|
@@ -350,12 +391,17 @@ module Stretchy
|
|
350
391
|
end
|
351
392
|
|
352
393
|
def aggregation(name, opts = {})
|
353
|
-
Jbuilder.new do |
|
394
|
+
Jbuilder.new do |agg_structure|
|
354
395
|
case
|
355
396
|
when opts.is_a?(Hash)
|
356
|
-
|
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
|
+
|
357
403
|
when opts.is_a?(Array)
|
358
|
-
extract_filter_arguments_from_array(
|
404
|
+
extract_filter_arguments_from_array(agg_structure, opts)
|
359
405
|
else
|
360
406
|
raise "#aggregation only accepts Hash or Array"
|
361
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
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Stretchy
|
2
|
+
module Relations
|
3
|
+
module QueryMethods
|
4
|
+
module Hybrid
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
# Perform a hybrid search using both neural and traditional queries.
|
7
|
+
#
|
8
|
+
# The `hybrid` method accepts two parameters: `neural` and `query`, both of which are arrays.
|
9
|
+
# The `neural` array should contain hashes representing neural queries, with each hash containing
|
10
|
+
# The `query` array should contain hashes representing traditional queries.
|
11
|
+
#
|
12
|
+
# ### Parameters
|
13
|
+
#
|
14
|
+
# - `opts:` The Hash options used to refine the selection (default: {}):
|
15
|
+
# - `:neural:` The Array of neural queries (default: []).
|
16
|
+
# - `:query:` The Array of traditional queries (default: []).
|
17
|
+
# Each element is a Hash representing a traditional query.
|
18
|
+
#
|
19
|
+
# ### Returns
|
20
|
+
# Returns a new relation with the hybrid search applied.
|
21
|
+
#
|
22
|
+
# ---
|
23
|
+
#
|
24
|
+
# ### Examples
|
25
|
+
#
|
26
|
+
# #### Hybrid search
|
27
|
+
#
|
28
|
+
# ```ruby
|
29
|
+
# Model.hybrid(
|
30
|
+
# neural: [
|
31
|
+
# {
|
32
|
+
# passage_embedding: 'hello world',
|
33
|
+
# model_id: '1234',
|
34
|
+
# k: 2
|
35
|
+
# }
|
36
|
+
# ],
|
37
|
+
# query: [
|
38
|
+
# {
|
39
|
+
# term: {
|
40
|
+
# status: :active
|
41
|
+
# }
|
42
|
+
# }
|
43
|
+
# ]
|
44
|
+
# )
|
45
|
+
# ```
|
46
|
+
#
|
47
|
+
def hybrid(opts)
|
48
|
+
spawn.hybrid!(opts)
|
49
|
+
end
|
50
|
+
|
51
|
+
def hybrid!(opts) # :nodoc:
|
52
|
+
self.hybrid_values = opts
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
QueryMethods.register!(:hybrid)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|