stretchy-model 0.6.5 → 0.6.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (165) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -1
  3. data/README.md +28 -10
  4. data/Rakefile +56 -0
  5. data/docs/.nojekyll +0 -0
  6. data/docs/README.md +147 -0
  7. data/docs/_coverpage.md +14 -0
  8. data/docs/_sidebar.md +14 -0
  9. data/docs/examples/_sidebar.md +15 -0
  10. data/docs/examples/data_analysis.md +216 -0
  11. data/docs/examples/semantic_search_with_llm.md +83 -0
  12. data/docs/examples/simple-ingest-pipeline.md +326 -0
  13. data/docs/guides/_sidebar.md +14 -0
  14. data/docs/guides/aggregations.md +142 -0
  15. data/docs/guides/machine-learning.md +154 -0
  16. data/docs/guides/models.md +372 -0
  17. data/docs/guides/pipelines.md +151 -0
  18. data/docs/guides/querying.md +361 -0
  19. data/docs/guides/quick-start.md +72 -0
  20. data/docs/guides/scopes.md +125 -0
  21. data/docs/index.html +113 -0
  22. data/docs/stretchy.cover.png +0 -0
  23. data/docs/stretchy.logo.png +0 -0
  24. data/docs/styles.css +90 -0
  25. data/lib/stretchy/attributes/transformers/keyword_transformer.rb +41 -35
  26. data/lib/stretchy/attributes/type/array.rb +24 -1
  27. data/lib/stretchy/attributes/type/base.rb +6 -2
  28. data/lib/stretchy/attributes/type/binary.rb +24 -17
  29. data/lib/stretchy/attributes/type/boolean.rb +29 -22
  30. data/lib/stretchy/attributes/type/completion.rb +18 -10
  31. data/lib/stretchy/attributes/type/constant_keyword.rb +35 -26
  32. data/lib/stretchy/attributes/type/date_time.rb +28 -17
  33. data/lib/stretchy/attributes/type/dense_vector.rb +46 -49
  34. data/lib/stretchy/attributes/type/flattened.rb +28 -19
  35. data/lib/stretchy/attributes/type/geo_point.rb +21 -12
  36. data/lib/stretchy/attributes/type/geo_shape.rb +21 -12
  37. data/lib/stretchy/attributes/type/hash.rb +24 -10
  38. data/lib/stretchy/attributes/type/histogram.rb +25 -0
  39. data/lib/stretchy/attributes/type/ip.rb +26 -17
  40. data/lib/stretchy/attributes/type/join.rb +16 -7
  41. data/lib/stretchy/attributes/type/keyword.rb +21 -26
  42. data/lib/stretchy/attributes/type/knn_vector.rb +47 -0
  43. data/lib/stretchy/attributes/type/match_only_text.rb +22 -1
  44. data/lib/stretchy/attributes/type/nested.rb +16 -11
  45. data/lib/stretchy/attributes/type/numeric/base.rb +30 -22
  46. data/lib/stretchy/attributes/type/numeric/byte.rb +20 -0
  47. data/lib/stretchy/attributes/type/numeric/double.rb +20 -0
  48. data/lib/stretchy/attributes/type/numeric/float.rb +20 -0
  49. data/lib/stretchy/attributes/type/numeric/half_float.rb +20 -0
  50. data/lib/stretchy/attributes/type/numeric/integer.rb +21 -1
  51. data/lib/stretchy/attributes/type/numeric/long.rb +20 -0
  52. data/lib/stretchy/attributes/type/numeric/scaled_float.rb +16 -7
  53. data/lib/stretchy/attributes/type/numeric/short.rb +20 -0
  54. data/lib/stretchy/attributes/type/numeric/unsigned_long.rb +21 -1
  55. data/lib/stretchy/attributes/type/percolator.rb +16 -4
  56. data/lib/stretchy/attributes/type/point.rb +19 -9
  57. data/lib/stretchy/attributes/type/range/base.rb +24 -1
  58. data/lib/stretchy/attributes/type/range/date_range.rb +21 -5
  59. data/lib/stretchy/attributes/type/range/double_range.rb +20 -4
  60. data/lib/stretchy/attributes/type/range/float_range.rb +21 -5
  61. data/lib/stretchy/attributes/type/range/integer_range.rb +20 -4
  62. data/lib/stretchy/attributes/type/range/ip_range.rb +20 -4
  63. data/lib/stretchy/attributes/type/range/long_range.rb +20 -4
  64. data/lib/stretchy/attributes/type/rank_feature.rb +16 -6
  65. data/lib/stretchy/attributes/type/rank_features.rb +16 -9
  66. data/lib/stretchy/attributes/type/search_as_you_type.rb +28 -18
  67. data/lib/stretchy/attributes/type/shape.rb +19 -9
  68. data/lib/stretchy/attributes/type/sparse_vector.rb +25 -21
  69. data/lib/stretchy/attributes/type/string.rb +42 -1
  70. data/lib/stretchy/attributes/type/text.rb +53 -28
  71. data/lib/stretchy/attributes/type/token_count.rb +21 -11
  72. data/lib/stretchy/attributes/type/version.rb +16 -6
  73. data/lib/stretchy/attributes/type/wildcard.rb +36 -25
  74. data/lib/stretchy/attributes.rb +29 -0
  75. data/lib/stretchy/delegation/gateway_delegation.rb +78 -0
  76. data/lib/stretchy/index_setting.rb +94 -0
  77. data/lib/stretchy/indexing/bulk.rb +75 -3
  78. data/lib/stretchy/model/callbacks.rb +1 -0
  79. data/lib/stretchy/model/common.rb +157 -0
  80. data/lib/stretchy/model/persistence.rb +144 -0
  81. data/lib/stretchy/model/refreshable.rb +26 -0
  82. data/lib/stretchy/pipeline.rb +2 -1
  83. data/lib/stretchy/pipelines/processor.rb +38 -36
  84. data/lib/stretchy/querying.rb +7 -8
  85. data/lib/stretchy/record.rb +5 -4
  86. data/lib/stretchy/relation.rb +229 -28
  87. data/lib/stretchy/relations/aggregation_methods/aggregation.rb +59 -0
  88. data/lib/stretchy/relations/aggregation_methods/avg.rb +45 -0
  89. data/lib/stretchy/relations/aggregation_methods/bucket_script.rb +47 -0
  90. data/lib/stretchy/relations/aggregation_methods/bucket_selector.rb +47 -0
  91. data/lib/stretchy/relations/aggregation_methods/bucket_sort.rb +47 -0
  92. data/lib/stretchy/relations/aggregation_methods/cardinality.rb +47 -0
  93. data/lib/stretchy/relations/aggregation_methods/children.rb +47 -0
  94. data/lib/stretchy/relations/aggregation_methods/composite.rb +41 -0
  95. data/lib/stretchy/relations/aggregation_methods/date_histogram.rb +53 -0
  96. data/lib/stretchy/relations/aggregation_methods/date_range.rb +53 -0
  97. data/lib/stretchy/relations/aggregation_methods/extended_stats.rb +48 -0
  98. data/lib/stretchy/relations/aggregation_methods/filter.rb +47 -0
  99. data/lib/stretchy/relations/aggregation_methods/filters.rb +47 -0
  100. data/lib/stretchy/relations/aggregation_methods/geo_bounds.rb +40 -0
  101. data/lib/stretchy/relations/aggregation_methods/geo_centroid.rb +40 -0
  102. data/lib/stretchy/relations/aggregation_methods/global.rb +39 -0
  103. data/lib/stretchy/relations/aggregation_methods/histogram.rb +43 -0
  104. data/lib/stretchy/relations/aggregation_methods/ip_range.rb +41 -0
  105. data/lib/stretchy/relations/aggregation_methods/max.rb +40 -0
  106. data/lib/stretchy/relations/aggregation_methods/min.rb +41 -0
  107. data/lib/stretchy/relations/aggregation_methods/missing.rb +40 -0
  108. data/lib/stretchy/relations/aggregation_methods/nested.rb +40 -0
  109. data/lib/stretchy/relations/aggregation_methods/percentile_ranks.rb +45 -0
  110. data/lib/stretchy/relations/aggregation_methods/percentiles.rb +45 -0
  111. data/lib/stretchy/relations/aggregation_methods/range.rb +42 -0
  112. data/lib/stretchy/relations/aggregation_methods/reverse_nested.rb +40 -0
  113. data/lib/stretchy/relations/aggregation_methods/sampler.rb +40 -0
  114. data/lib/stretchy/relations/aggregation_methods/scripted_metric.rb +43 -0
  115. data/lib/stretchy/relations/aggregation_methods/significant_terms.rb +45 -0
  116. data/lib/stretchy/relations/aggregation_methods/stats.rb +42 -0
  117. data/lib/stretchy/relations/aggregation_methods/sum.rb +42 -0
  118. data/lib/stretchy/relations/aggregation_methods/terms.rb +46 -0
  119. data/lib/stretchy/relations/aggregation_methods/top_hits.rb +42 -0
  120. data/lib/stretchy/relations/aggregation_methods/top_metrics.rb +44 -0
  121. data/lib/stretchy/relations/aggregation_methods/value_count.rb +41 -0
  122. data/lib/stretchy/relations/aggregation_methods/weighted_avg.rb +42 -0
  123. data/lib/stretchy/relations/aggregation_methods.rb +20 -749
  124. data/lib/stretchy/relations/finder_methods.rb +2 -18
  125. data/lib/stretchy/relations/null_relation.rb +55 -0
  126. data/lib/stretchy/relations/query_builder.rb +82 -36
  127. data/lib/stretchy/relations/query_methods/bind.rb +19 -0
  128. data/lib/stretchy/relations/query_methods/extending.rb +29 -0
  129. data/lib/stretchy/relations/query_methods/fields.rb +70 -0
  130. data/lib/stretchy/relations/query_methods/filter_query.rb +53 -0
  131. data/lib/stretchy/relations/query_methods/has_field.rb +40 -0
  132. data/lib/stretchy/relations/query_methods/highlight.rb +75 -0
  133. data/lib/stretchy/relations/query_methods/hybrid.rb +60 -0
  134. data/lib/stretchy/relations/query_methods/ids.rb +40 -0
  135. data/lib/stretchy/relations/query_methods/match.rb +52 -0
  136. data/lib/stretchy/relations/query_methods/must_not.rb +54 -0
  137. data/lib/stretchy/relations/query_methods/neural.rb +58 -0
  138. data/lib/stretchy/relations/query_methods/neural_sparse.rb +43 -0
  139. data/lib/stretchy/relations/query_methods/none.rb +21 -0
  140. data/lib/stretchy/relations/query_methods/or_filter.rb +21 -0
  141. data/lib/stretchy/relations/query_methods/order.rb +63 -0
  142. data/lib/stretchy/relations/query_methods/query_string.rb +44 -0
  143. data/lib/stretchy/relations/query_methods/regexp.rb +61 -0
  144. data/lib/stretchy/relations/query_methods/should.rb +51 -0
  145. data/lib/stretchy/relations/query_methods/size.rb +44 -0
  146. data/lib/stretchy/relations/query_methods/skip_callbacks.rb +47 -0
  147. data/lib/stretchy/relations/query_methods/source.rb +59 -0
  148. data/lib/stretchy/relations/query_methods/where.rb +113 -0
  149. data/lib/stretchy/relations/query_methods.rb +48 -569
  150. data/lib/stretchy/relations/scoping/default.rb +136 -0
  151. data/lib/stretchy/relations/scoping/named.rb +70 -0
  152. data/lib/stretchy/relations/scoping/scope_registry.rb +36 -0
  153. data/lib/stretchy/relations/scoping.rb +30 -0
  154. data/lib/stretchy/relations/search_option_methods.rb +2 -0
  155. data/lib/stretchy/version.rb +1 -1
  156. data/lib/stretchy.rb +17 -10
  157. metadata +111 -17
  158. data/lib/stretchy/common.rb +0 -38
  159. data/lib/stretchy/null_relation.rb +0 -53
  160. data/lib/stretchy/persistence.rb +0 -43
  161. data/lib/stretchy/refreshable.rb +0 -15
  162. data/lib/stretchy/scoping/default.rb +0 -134
  163. data/lib/stretchy/scoping/named.rb +0 -68
  164. data/lib/stretchy/scoping/scope_registry.rb +0 -34
  165. 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[:field]
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.nil? && must_nots.nil? && shoulds.nil? && regexes.nil?
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
- hybrid[:neural].each do |n|
134
- structure.child! do
135
- params = n.dup
136
- field_name, query_text = params.shift
137
- structure.neural do
138
- structure.set! field_name do
139
- structure.query_text query_text
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
- hybrid[:query].each do |query|
147
- structure.child! do
148
- structure.extract! query, *query.keys
149
- end
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 unless regexes.nil?
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
- structure.aggregations do
262
- aggregations.each do |agg|
263
- structure.set! agg[:name], aggregation(agg[:name], keyword_transformer.transform(agg[:args], :name))
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 : values[:default_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
- # If v is an array, we build a terms query otherwise a term query
307
- _must << (v.is_a?(Array) ? {terms: Hash[k,v]} : {term: Hash[k,v]})
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
- _and << "(#{arg})" if arg.class == String
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 |agg|
394
+ Jbuilder.new do |agg_structure|
354
395
  case
355
396
  when opts.is_a?(Hash)
356
- agg.extract! opts, *opts.keys
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(agg, opts)
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