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.
Files changed (212) 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 +15 -0
  9. data/docs/examples/_sidebar.md +15 -0
  10. data/docs/examples/data_analysis.md +216 -0
  11. data/docs/examples/neural_search_with_llm.md +381 -0
  12. data/docs/examples/simple-ingest-pipeline.md +326 -0
  13. data/docs/guides/_sidebar.md +15 -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/elasticsearch/api/actions/connector/check_in.rb +64 -0
  26. data/lib/elasticsearch/api/actions/connector/delete.rb +64 -0
  27. data/lib/elasticsearch/api/actions/connector/get.rb +64 -0
  28. data/lib/elasticsearch/api/actions/connector/last_sync.rb +66 -0
  29. data/lib/elasticsearch/api/actions/connector/list.rb +60 -0
  30. data/lib/elasticsearch/api/actions/connector/post.rb +57 -0
  31. data/lib/elasticsearch/api/actions/connector/put.rb +66 -0
  32. data/lib/elasticsearch/api/actions/connector/update_api_key_id.rb +66 -0
  33. data/lib/elasticsearch/api/actions/connector/update_configuration.rb +66 -0
  34. data/lib/elasticsearch/api/actions/connector/update_error.rb +66 -0
  35. data/lib/elasticsearch/api/actions/connector/update_filtering.rb +66 -0
  36. data/lib/elasticsearch/api/actions/connector/update_index_name.rb +66 -0
  37. data/lib/elasticsearch/api/actions/connector/update_name.rb +66 -0
  38. data/lib/elasticsearch/api/actions/connector/update_native.rb +66 -0
  39. data/lib/elasticsearch/api/actions/connector/update_pipeline.rb +66 -0
  40. data/lib/elasticsearch/api/actions/connector/update_scheduling.rb +66 -0
  41. data/lib/elasticsearch/api/actions/connector/update_service_type.rb +66 -0
  42. data/lib/elasticsearch/api/actions/connector/update_status.rb +66 -0
  43. data/lib/elasticsearch/api/namespace/connector.rb +36 -0
  44. data/lib/opensearch/api/actions/machine_learning/connector/delete.rb +42 -0
  45. data/lib/opensearch/api/actions/machine_learning/connector/get.rb +42 -0
  46. data/lib/opensearch/api/actions/machine_learning/connector/list.rb +38 -0
  47. data/lib/opensearch/api/actions/machine_learning/connector/post.rb +35 -0
  48. data/lib/opensearch/api/actions/machine_learning/connector/put.rb +44 -0
  49. data/lib/opensearch/api/actions/machine_learning/models/predict.rb +32 -0
  50. data/lib/opensearch/api/namespace/connector.rb +19 -0
  51. data/lib/stretchy/attributes/transformers/keyword_transformer.rb +41 -35
  52. data/lib/stretchy/attributes/type/array.rb +24 -1
  53. data/lib/stretchy/attributes/type/base.rb +6 -2
  54. data/lib/stretchy/attributes/type/binary.rb +24 -17
  55. data/lib/stretchy/attributes/type/boolean.rb +29 -22
  56. data/lib/stretchy/attributes/type/completion.rb +18 -10
  57. data/lib/stretchy/attributes/type/constant_keyword.rb +35 -26
  58. data/lib/stretchy/attributes/type/date_time.rb +28 -17
  59. data/lib/stretchy/attributes/type/dense_vector.rb +46 -49
  60. data/lib/stretchy/attributes/type/flattened.rb +28 -19
  61. data/lib/stretchy/attributes/type/geo_point.rb +21 -12
  62. data/lib/stretchy/attributes/type/geo_shape.rb +21 -12
  63. data/lib/stretchy/attributes/type/hash.rb +24 -10
  64. data/lib/stretchy/attributes/type/histogram.rb +25 -0
  65. data/lib/stretchy/attributes/type/ip.rb +26 -17
  66. data/lib/stretchy/attributes/type/join.rb +16 -7
  67. data/lib/stretchy/attributes/type/keyword.rb +21 -26
  68. data/lib/stretchy/attributes/type/knn_vector.rb +47 -0
  69. data/lib/stretchy/attributes/type/match_only_text.rb +22 -1
  70. data/lib/stretchy/attributes/type/nested.rb +16 -11
  71. data/lib/stretchy/attributes/type/numeric/base.rb +30 -22
  72. data/lib/stretchy/attributes/type/numeric/byte.rb +20 -0
  73. data/lib/stretchy/attributes/type/numeric/double.rb +20 -0
  74. data/lib/stretchy/attributes/type/numeric/float.rb +20 -0
  75. data/lib/stretchy/attributes/type/numeric/half_float.rb +20 -0
  76. data/lib/stretchy/attributes/type/numeric/integer.rb +21 -1
  77. data/lib/stretchy/attributes/type/numeric/long.rb +20 -0
  78. data/lib/stretchy/attributes/type/numeric/scaled_float.rb +16 -7
  79. data/lib/stretchy/attributes/type/numeric/short.rb +20 -0
  80. data/lib/stretchy/attributes/type/numeric/unsigned_long.rb +21 -1
  81. data/lib/stretchy/attributes/type/percolator.rb +16 -4
  82. data/lib/stretchy/attributes/type/point.rb +19 -9
  83. data/lib/stretchy/attributes/type/range/base.rb +24 -1
  84. data/lib/stretchy/attributes/type/range/date_range.rb +21 -5
  85. data/lib/stretchy/attributes/type/range/double_range.rb +20 -4
  86. data/lib/stretchy/attributes/type/range/float_range.rb +21 -5
  87. data/lib/stretchy/attributes/type/range/integer_range.rb +20 -4
  88. data/lib/stretchy/attributes/type/range/ip_range.rb +20 -4
  89. data/lib/stretchy/attributes/type/range/long_range.rb +20 -4
  90. data/lib/stretchy/attributes/type/rank_feature.rb +16 -6
  91. data/lib/stretchy/attributes/type/rank_features.rb +16 -9
  92. data/lib/stretchy/attributes/type/search_as_you_type.rb +28 -18
  93. data/lib/stretchy/attributes/type/shape.rb +19 -9
  94. data/lib/stretchy/attributes/type/sparse_vector.rb +25 -21
  95. data/lib/stretchy/attributes/type/string.rb +42 -1
  96. data/lib/stretchy/attributes/type/text.rb +53 -28
  97. data/lib/stretchy/attributes/type/token_count.rb +21 -11
  98. data/lib/stretchy/attributes/type/version.rb +16 -6
  99. data/lib/stretchy/attributes/type/wildcard.rb +36 -25
  100. data/lib/stretchy/attributes.rb +29 -0
  101. data/lib/stretchy/delegation/gateway_delegation.rb +78 -0
  102. data/lib/stretchy/index_setting.rb +94 -0
  103. data/lib/stretchy/indexing/bulk.rb +75 -3
  104. data/lib/stretchy/machine_learning/connector.rb +130 -0
  105. data/lib/stretchy/machine_learning/errors.rb +25 -0
  106. data/lib/stretchy/machine_learning/model.rb +162 -109
  107. data/lib/stretchy/machine_learning/registry.rb +19 -0
  108. data/lib/stretchy/model/callbacks.rb +1 -0
  109. data/lib/stretchy/model/common.rb +157 -0
  110. data/lib/stretchy/model/persistence.rb +144 -0
  111. data/lib/stretchy/model/refreshable.rb +26 -0
  112. data/lib/stretchy/open_search_compatibility.rb +2 -0
  113. data/lib/stretchy/pipeline.rb +2 -1
  114. data/lib/stretchy/pipelines/processor.rb +40 -36
  115. data/lib/stretchy/querying.rb +7 -8
  116. data/lib/stretchy/rails/railtie.rb +11 -0
  117. data/lib/stretchy/rails/tasks/connector/create.rake +32 -0
  118. data/lib/stretchy/rails/tasks/connector/delete.rake +27 -0
  119. data/lib/stretchy/rails/tasks/connector/status.rake +31 -0
  120. data/lib/stretchy/rails/tasks/connector/update.rake +32 -0
  121. data/lib/stretchy/rails/tasks/index/create.rake +28 -0
  122. data/lib/stretchy/rails/tasks/index/delete.rake +27 -0
  123. data/lib/stretchy/rails/tasks/index/status.rake +23 -0
  124. data/lib/stretchy/rails/tasks/ml/delete.rake +25 -0
  125. data/lib/stretchy/rails/tasks/ml/deploy.rake +78 -0
  126. data/lib/stretchy/rails/tasks/ml/status.rake +31 -0
  127. data/lib/stretchy/rails/tasks/pipeline/create.rake +27 -0
  128. data/lib/stretchy/rails/tasks/pipeline/delete.rake +26 -0
  129. data/lib/stretchy/rails/tasks/pipeline/status.rake +25 -0
  130. data/lib/stretchy/rails/tasks/status.rake +15 -0
  131. data/lib/stretchy/rails/tasks/stretchy.rake +42 -0
  132. data/lib/stretchy/record.rb +5 -4
  133. data/lib/stretchy/relation.rb +229 -28
  134. data/lib/stretchy/relations/aggregation_methods/aggregation.rb +59 -0
  135. data/lib/stretchy/relations/aggregation_methods/avg.rb +45 -0
  136. data/lib/stretchy/relations/aggregation_methods/bucket_script.rb +47 -0
  137. data/lib/stretchy/relations/aggregation_methods/bucket_selector.rb +47 -0
  138. data/lib/stretchy/relations/aggregation_methods/bucket_sort.rb +47 -0
  139. data/lib/stretchy/relations/aggregation_methods/cardinality.rb +47 -0
  140. data/lib/stretchy/relations/aggregation_methods/children.rb +47 -0
  141. data/lib/stretchy/relations/aggregation_methods/composite.rb +41 -0
  142. data/lib/stretchy/relations/aggregation_methods/date_histogram.rb +53 -0
  143. data/lib/stretchy/relations/aggregation_methods/date_range.rb +53 -0
  144. data/lib/stretchy/relations/aggregation_methods/extended_stats.rb +48 -0
  145. data/lib/stretchy/relations/aggregation_methods/filter.rb +47 -0
  146. data/lib/stretchy/relations/aggregation_methods/filters.rb +47 -0
  147. data/lib/stretchy/relations/aggregation_methods/geo_bounds.rb +40 -0
  148. data/lib/stretchy/relations/aggregation_methods/geo_centroid.rb +40 -0
  149. data/lib/stretchy/relations/aggregation_methods/global.rb +39 -0
  150. data/lib/stretchy/relations/aggregation_methods/histogram.rb +43 -0
  151. data/lib/stretchy/relations/aggregation_methods/ip_range.rb +41 -0
  152. data/lib/stretchy/relations/aggregation_methods/max.rb +40 -0
  153. data/lib/stretchy/relations/aggregation_methods/min.rb +41 -0
  154. data/lib/stretchy/relations/aggregation_methods/missing.rb +40 -0
  155. data/lib/stretchy/relations/aggregation_methods/nested.rb +40 -0
  156. data/lib/stretchy/relations/aggregation_methods/percentile_ranks.rb +45 -0
  157. data/lib/stretchy/relations/aggregation_methods/percentiles.rb +45 -0
  158. data/lib/stretchy/relations/aggregation_methods/range.rb +42 -0
  159. data/lib/stretchy/relations/aggregation_methods/reverse_nested.rb +40 -0
  160. data/lib/stretchy/relations/aggregation_methods/sampler.rb +40 -0
  161. data/lib/stretchy/relations/aggregation_methods/scripted_metric.rb +43 -0
  162. data/lib/stretchy/relations/aggregation_methods/significant_terms.rb +45 -0
  163. data/lib/stretchy/relations/aggregation_methods/stats.rb +42 -0
  164. data/lib/stretchy/relations/aggregation_methods/sum.rb +42 -0
  165. data/lib/stretchy/relations/aggregation_methods/terms.rb +46 -0
  166. data/lib/stretchy/relations/aggregation_methods/top_hits.rb +42 -0
  167. data/lib/stretchy/relations/aggregation_methods/top_metrics.rb +44 -0
  168. data/lib/stretchy/relations/aggregation_methods/value_count.rb +41 -0
  169. data/lib/stretchy/relations/aggregation_methods/weighted_avg.rb +42 -0
  170. data/lib/stretchy/relations/aggregation_methods.rb +20 -749
  171. data/lib/stretchy/relations/finder_methods.rb +2 -18
  172. data/lib/stretchy/relations/null_relation.rb +55 -0
  173. data/lib/stretchy/relations/query_builder.rb +82 -36
  174. data/lib/stretchy/relations/query_methods/bind.rb +19 -0
  175. data/lib/stretchy/relations/query_methods/extending.rb +29 -0
  176. data/lib/stretchy/relations/query_methods/fields.rb +70 -0
  177. data/lib/stretchy/relations/query_methods/filter_query.rb +53 -0
  178. data/lib/stretchy/relations/query_methods/has_field.rb +40 -0
  179. data/lib/stretchy/relations/query_methods/highlight.rb +75 -0
  180. data/lib/stretchy/relations/query_methods/hybrid.rb +60 -0
  181. data/lib/stretchy/relations/query_methods/ids.rb +40 -0
  182. data/lib/stretchy/relations/query_methods/match.rb +52 -0
  183. data/lib/stretchy/relations/query_methods/must_not.rb +54 -0
  184. data/lib/stretchy/relations/query_methods/neural.rb +58 -0
  185. data/lib/stretchy/relations/query_methods/neural_sparse.rb +43 -0
  186. data/lib/stretchy/relations/query_methods/none.rb +21 -0
  187. data/lib/stretchy/relations/query_methods/or_filter.rb +21 -0
  188. data/lib/stretchy/relations/query_methods/order.rb +63 -0
  189. data/lib/stretchy/relations/query_methods/query_string.rb +44 -0
  190. data/lib/stretchy/relations/query_methods/regexp.rb +61 -0
  191. data/lib/stretchy/relations/query_methods/should.rb +51 -0
  192. data/lib/stretchy/relations/query_methods/size.rb +44 -0
  193. data/lib/stretchy/relations/query_methods/skip_callbacks.rb +47 -0
  194. data/lib/stretchy/relations/query_methods/source.rb +59 -0
  195. data/lib/stretchy/relations/query_methods/where.rb +113 -0
  196. data/lib/stretchy/relations/query_methods.rb +48 -569
  197. data/lib/stretchy/relations/scoping/default.rb +136 -0
  198. data/lib/stretchy/relations/scoping/named.rb +70 -0
  199. data/lib/stretchy/relations/scoping/scope_registry.rb +36 -0
  200. data/lib/stretchy/relations/scoping.rb +30 -0
  201. data/lib/stretchy/relations/search_option_methods.rb +2 -0
  202. data/lib/stretchy/version.rb +1 -1
  203. data/lib/stretchy.rb +24 -10
  204. metadata +170 -17
  205. data/lib/stretchy/common.rb +0 -38
  206. data/lib/stretchy/null_relation.rb +0 -53
  207. data/lib/stretchy/persistence.rb +0 -43
  208. data/lib/stretchy/refreshable.rb +0 -15
  209. data/lib/stretchy/scoping/default.rb +0 -134
  210. data/lib/stretchy/scoping/named.rb +0 -68
  211. data/lib/stretchy/scoping/scope_registry.rb +0 -34
  212. data/lib/stretchy/scoping.rb +0 -28
@@ -18,6 +18,33 @@ module Stretchy
18
18
  :count,
19
19
  to: :gateway
20
20
 
21
+ # This method is used to set or retrieve the index name for the Elasticsearch index.
22
+ #
23
+ # ### Parameters
24
+ #
25
+ # - `name:` (String, nil) - The name to set for the index. If nil, the method will act as a getter.
26
+ # - `&block:` A block that returns the index name when called.
27
+ #
28
+ # ### Returns
29
+ #
30
+ # - (String) - The index name.
31
+ #
32
+ # ### Behavior
33
+ #
34
+ # - If a name or block is provided, it sets the index name to the provided name or block.
35
+ # - If no argument is provided, it retrieves the index name.
36
+ # - If the index name is callable (e.g., a Proc), it calls the block.
37
+ # - If the index name is not set, it defaults to the parameterized and underscored collection name of the base class model.
38
+ #
39
+ # ### Example
40
+ #
41
+ # In this example, the index name for instances of `MyModel` will be "my_custom_index" instead of "my_models".
42
+ #
43
+ # ```ruby
44
+ # class MyModel < Stretchy::Record
45
+ # index_name "my_custom_index"
46
+ # end
47
+ # ```
21
48
  def index_name(name=nil, &block)
22
49
  if name || block_given?
23
50
  return (@index_name = name || block)
@@ -30,6 +57,30 @@ module Stretchy
30
57
  end
31
58
  end
32
59
 
60
+ # This method is used to set or retrieve the settings for the Elasticsearch index.
61
+ #
62
+ # ### Parameters
63
+ #
64
+ # - `settings:` (Hash) - The settings to set for the index. If empty, the method will act as a getter.
65
+ #
66
+ # ### Returns
67
+ #
68
+ # - (Hash) - The index settings.
69
+ #
70
+ # ### Behavior
71
+ #
72
+ # - If settings are provided, it sets the index settings to the provided settings.
73
+ # - If no argument is provided, it retrieves the index settings.
74
+ # - If the `default_pipeline` is set, it merges it into the index settings.
75
+ #
76
+ # ### Example
77
+ #
78
+ # ```ruby
79
+ # class MyModel < Stretchy::Record
80
+ # index_settings number_of_shards: 5, number_of_replicas: 1
81
+ # end
82
+ # ```
83
+ # In this example, the index settings for instances of `MyModel` will have 5 shards and 1 replica.
33
84
  def index_settings(settings={})
34
85
  @index_settings ||= settings
35
86
  @index_settings.merge!(default_pipeline: default_pipeline.to_s) if default_pipeline
@@ -40,6 +91,33 @@ module Stretchy
40
91
  @gateway = nil
41
92
  end
42
93
 
94
+ # This method is used to access the underlying `Stretchy::Repository` for the model. It creates the repository if it doesn't exist, and reuses it if it does.
95
+ #
96
+ # ### Parameters
97
+ #
98
+ # - `&block:` (optional) A block that is evaluated in the context of the repository. This can be used to perform operations on the repository.
99
+ #
100
+ # ### Returns
101
+ #
102
+ # - (Stretchy::Repository) - The repository for the model.
103
+ #
104
+ # ### Behavior
105
+ #
106
+ # - If the repository doesn't exist or if the client of the existing repository is not the current client from the Stretchy configuration,
107
+ # it creates a new repository with the current `client`, `index_name`, `class`, `mapping`, and `settings`.
108
+ # - If a block is given, it is evaluated in the context of the repository.
109
+ # - It always returns the repository.
110
+ #
111
+ # ### Example
112
+ #
113
+ # ```ruby
114
+ # class MyModel < Stretchy::Record
115
+ # gateway do
116
+ # # Perform operations on the repository
117
+ # end
118
+ # end
119
+ # ```
120
+ #
43
121
  def gateway(&block)
44
122
  reload_gateway_configuration! if @gateway && @gateway.client != Stretchy.configuration.client
45
123
 
@@ -0,0 +1,94 @@
1
+ module Stretchy
2
+ # This class is used to define settings for an Elasticsearch index.
3
+ # It provides methods to define analyzers, filters, tokenizers, and normalizers.
4
+ #
5
+ # ## Usage
6
+ # ```ruby
7
+ # class MyIndexSetting < Stretchy::IndexSetting
8
+ # analyzer :default,
9
+ # filter: [:lowercase, :asciifolding],
10
+ # tokenizer: :standard
11
+ #
12
+ # filter :my_stemmer,
13
+ # type: :stemmer,
14
+ # name: :light_english
15
+ #
16
+ # tokenizer :path_tokenizer,
17
+ # type: :path_hierarchy,
18
+ # reverse: true
19
+ #
20
+ # normalizer :my_normalizer,
21
+ # type: :custom,
22
+ # filter: [:lowercase]
23
+ # end
24
+ # ```
25
+ #
26
+ # In this example, we define a custom index setting `MyIndexSetting` that includes a default analyzer, a custom filter, a custom tokenizer, and a custom normalizer.
27
+ #
28
+ # ## Methods
29
+ # - `analyzer(name, options)`: Defines an analyzer with the given name and options.
30
+ # - `filter(name, options)`: Defines a filter with the given name and options.
31
+ # - `tokenizer(name, options)`: Defines a tokenizer with the given name and options.
32
+ # - `normalizer(name, options)`: Defines a normalizer with the given name and options.
33
+ #
34
+ # Each of these methods takes a name as the first argument and a hash of options as the second argument. The options will depend on the specific type of analyzer, filter, tokenizer, or normalizer being defined.
35
+ #
36
+ # ### Accessing Defined Settings
37
+ # You can access the settings defined in an `IndexSetting` subclass using the `analyzers`, `filters`, `tokenizers`, and `normalizers` methods. These methods return a hash of the defined settings for their respective type.
38
+ #
39
+ # ```ruby
40
+ # MyIndexSetting.analyzers
41
+ # # => { default: { filter: [:lowercase, :asciifolding], tokenizer: :standard } }
42
+ # ```
43
+ #
44
+ # ```ruby
45
+ # MyIndexSetting.filters
46
+ # # => { my_stemmer: { type: :stemmer, name: :light_english } }
47
+ # ```
48
+ #
49
+ # ```ruby
50
+ # MyIndexSetting.tokenizers
51
+ # # => { path_tokenizer: { type: :path_hierarchy, reverse: true } }
52
+ # ```
53
+ #
54
+ # ```ruby
55
+ # MyIndexSetting.normalizers
56
+ # # => { my_normalizer: { type: :custom, filter: [:lowercase] } }
57
+ # ```
58
+ # ### Using the Settings
59
+ # You can use the settings defined in an `IndexSetting` subclass to configure the settings for a `StretchyModel`.
60
+ #
61
+ # ```ruby
62
+ # class MyModel < StretchyModel
63
+ # index_settings(MyIndexSetting.as_json)
64
+ # end
65
+ # ```
66
+ #
67
+ class IndexSetting
68
+ class << self
69
+ METHODS = [:analyzer, :filter, :tokenizer, :normalizer]
70
+
71
+ def settings
72
+ @settings ||= {}
73
+ end
74
+
75
+ def as_json
76
+ {
77
+ self.name.demodulize.underscore.to_sym => settings
78
+ }
79
+ end
80
+
81
+ METHODS.each do |method|
82
+ define_method(method) do |*args|
83
+ settings[method] ||= {}
84
+ settings[method][args.shift] = Hash[*args] unless args.empty?
85
+ end
86
+
87
+ define_method("#{method}s") do
88
+ settings[method] || {}
89
+ end
90
+ end
91
+
92
+ end
93
+ end
94
+ end
@@ -4,15 +4,62 @@ module Stretchy
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  class_methods do
7
-
7
+ # used to bulk index a collection of records.
8
+ #
9
+ # ### Parameters
10
+ #
11
+ # - `records:` (Array) - The collection of records to be indexed.
12
+ #
13
+ # ### Returns
14
+ #
15
+ # - (Hash) - The response from Elasticsearch after performing the bulk operation.
16
+ #
17
+ # ### Behavior
18
+ #
19
+ # The method sends a bulk request to Elasticsearch with the provided records. The records should be an array of hashes, where each hash describes a single create, index, delete, or update operation.
20
+ # It always returns the response from Elasticsearch.
21
+ #
22
+ # ### Example
23
+ #
24
+ # ```ruby
25
+ # records = [
26
+ # { index: { _index: 'my_index', _id: 1, data: { title: 'foo' } } },
27
+ # { index: { _index: 'my_index', _id: 2, data: { title: 'bar' } } }
28
+ # ]
29
+ # MyModel.bulk(records)
30
+ # ```
31
+ # In this example, the `bulk` method is used to index two records into 'my_index'.
8
32
  def bulk(records)
9
33
  self.gateway.client.bulk body: records
10
34
  end
11
35
 
12
- # bulk_in_batches(records, size: 100) do |batch|
36
+ # used to bulk index a collection of records in batches.
37
+ #
38
+ # ### Parameters
39
+ #
40
+ # - `records:` (Array) - The collection of records to be indexed.
41
+ # - `size:` (Integer) - The size of the batches. Defaults to 1000.
42
+ # - `&block:` (optional) A block that is evaluated for each batch. This can be used to perform operations on each batch.
43
+ #
44
+ # ### Returns
45
+ #
46
+ # - (Array) - The results of the bulk operations.
47
+ #
48
+ # ### Behavior
49
+ #
50
+ # - The method splits the records into batches of the specified size. For each batch, if a block is given, it is evaluated with the batch as argument. Then, the batch is indexed using the `bulk` method.
51
+ # - After all batches have been processed, it refreshes the index to make the changes available for search.
52
+ #
53
+ # ### Example
54
+ #
55
+ # ```ruby
56
+ # records = [Report.new(title: "hello"), Report.new(title: "world"), Report.new(title: "goodbye")]
57
+ # MyModel.bulk_in_batches(records, size: 100) do |batch|
13
58
  # # do something with the batch
14
- # batch.each { |record| record.to_bulk(method)}
59
+ # batch.map! { |record| record.to_bulk(:index)}
15
60
  # end
61
+ # ```
62
+ # In this example, the `bulk_in_batches` method is used to index the `records` in batches of 100.
16
63
  def bulk_in_batches(records, size: 1000)
17
64
  bulk_results = records.each_slice(size).map do |batch|
18
65
  yield batch if block_given?
@@ -32,6 +79,31 @@ module Stretchy
32
79
  # end
33
80
  end
34
81
 
82
+ # used to transform a record into a hash suitable for bulk operations.
83
+ #
84
+ # ### Parameters
85
+ #
86
+ # - `method:` (Symbol) - The operation to be performed. Can be `:index`, `:delete`, or `:update`. Defaults to `:index`.
87
+ #
88
+ # ### Returns
89
+ #
90
+ # - (Hash) - The hash representing the record for the bulk operation.
91
+ #
92
+ # ### Behavior
93
+ #
94
+ # The method transforms the record into a hash that describes the operation to be performed on the record. The operation is specified by the `method` parameter.
95
+ # For `:index`, it includes the index name and the record data (excluding the id).
96
+ # For `:delete`, it includes the index name and the record id.
97
+ # For `:update`, it includes the index name, the record id, and the record data (excluding the id).
98
+ #
99
+ # ### Example
100
+ #
101
+ # ```ruby
102
+ # record = MyModel.new(title: "hello")
103
+ # record.to_bulk(:index)
104
+ # # => { index: { _index: "my_models", data: { title: "hello" } } }
105
+ # ```
106
+ # In this example, the `to_bulk` method is used to transform a `MyModel` instance into a hash suitable for an index operation in a bulk request.
35
107
  def to_bulk(method = :index)
36
108
  case method
37
109
  when :index
@@ -0,0 +1,130 @@
1
+ module Stretchy
2
+ module MachineLearning
3
+ class Connector
4
+
5
+ cattr_reader :client do
6
+ Stretchy.configuration.client.connector
7
+ end
8
+
9
+ class Settings
10
+ def initialize(valid_keys = [])
11
+ @valid_keys = valid_keys
12
+ @settings = {}
13
+ end
14
+
15
+ def as_json(*)
16
+ @settings.as_json
17
+ end
18
+
19
+ def method_missing(method, *args, &block)
20
+ if block_given?
21
+ @settings[method] = self.class.new.tap { |obj| obj.instance_eval(&block) }
22
+ elsif args.empty?
23
+ value = @settings[method]
24
+ value.is_a?(Hash) ? Elasticsearch::Model::HashWrapper[value] : value
25
+ elsif args.length == 1 && @valid_keys.empty? || @valid_keys.include?(method)
26
+ @settings[method] = args.first
27
+ else
28
+ super
29
+ end
30
+ end
31
+
32
+ def respond_to_missing?(method, include_private = false)
33
+ @settings.key?(method) || super
34
+ end
35
+ end
36
+
37
+ class << self
38
+ include Errors
39
+
40
+ METHODS = [
41
+ :description,
42
+ :version,
43
+ :protocol,
44
+ :credentials,
45
+ :parameters,
46
+ :actions,
47
+ :name
48
+ ].freeze
49
+
50
+ def settings
51
+ @settings ||= Settings.new(METHODS)
52
+ end
53
+
54
+ delegate *METHODS, to: :settings
55
+
56
+ def name(name = nil)
57
+ settings.name(name) if name
58
+ settings.name || to_s.split('::').last.underscore
59
+ end
60
+
61
+ def registry
62
+ @registery ||= Stretchy::MachineLearning::Registry.register(class_name: self.name, class_type: 'connector')
63
+ end
64
+
65
+ def id
66
+ @id || registry.model_id
67
+ end
68
+
69
+ concerning :API do
70
+ def create!
71
+ response = client.post(body: self.to_hash.as_json).with_indifferent_access
72
+ registry.update(model_id: response.dig(:connector_id))
73
+ @id = response.dig(:connector_id)
74
+ end
75
+
76
+ def delete!
77
+ begin
78
+ response = client.delete(connector_id: self.id).with_indifferent_access
79
+ rescue "#{Stretchy.configuration.search_backend_const}::Transport::Transport::Errors::NotFound".constantize => e
80
+ raise Stretchy::MachineLearning::Errors::ConnectorMissingError
81
+
82
+ ensure
83
+ if response.dig(:result) == 'deleted'
84
+ registry.delete
85
+ @registry = nil
86
+ @id = nil
87
+ end
88
+ response
89
+ end
90
+ end
91
+
92
+ def update!
93
+ client.put(connector_id: self.id, body: self.to_hash)
94
+ end
95
+
96
+ def find(id = nil)
97
+ begin
98
+ id = self.id if id.nil?
99
+ client.get(connector_id: id)
100
+ rescue ArgumentError => e
101
+ raise Stretchy::MachineLearning::Errors::ConnectorMissingError
102
+ rescue "#{Stretchy.configuration.search_backend_const}::Transport::Transport::Errors::NotFound".constantize => e
103
+ # raise Stretchy::MachineLearning::Errors::ConnectorMissingError
104
+ end
105
+ end
106
+
107
+ def exists?
108
+ self.find(self.id).present?
109
+ end
110
+
111
+ def to_hash
112
+ acts = self.actions.as_json
113
+ acts[:request_body] = actions[:request_body]
114
+ {
115
+ name: self.name,
116
+ description: self.description,
117
+ version: self.version,
118
+ protocol: self.protocol,
119
+ credential: self.credentials,
120
+ parameters: self.parameters,
121
+ actions: [acts]
122
+ }.compact
123
+
124
+ end
125
+ end
126
+
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,25 @@
1
+ module Stretchy::MachineLearning::Errors
2
+ class ModelNotDeployedError < StandardError
3
+ def initialize(msg="Model is not deployed. Please run `rake stretchy:ml:deploy` to deploy it.")
4
+ super
5
+ end
6
+ end
7
+
8
+ class ModelNotRegisteredError < StandardError
9
+ def initialize(msg="Model is not registered. Please run `rake stretchy:ml:register` to register it.")
10
+ super
11
+ end
12
+ end
13
+
14
+ class ConnectorMissingError < StandardError
15
+ def initialize(msg="Connector is missing. Please run `rake stretchy:ml:connector:create` to create it.")
16
+ super
17
+ end
18
+ end
19
+
20
+ class AgentNotRegisteredError < StandardError
21
+ def initialize(msg="Agent is not registered. Please run `rake stretchy:ml:agent:create` to create it.")
22
+ super
23
+ end
24
+ end
25
+ end