opensearch-sugar 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.agents/skills/diataxis/SKILL.md +142 -0
  3. data/.agents/skills/diataxis/references/examples.md +420 -0
  4. data/.agents/skills/diataxis/references/explanation-template.md +96 -0
  5. data/.agents/skills/diataxis/references/framework.md +400 -0
  6. data/.agents/skills/diataxis/references/how-to-guide-template.md +105 -0
  7. data/.agents/skills/diataxis/references/reference-template.md +110 -0
  8. data/.agents/skills/diataxis/references/tutorial-template.md +101 -0
  9. data/.agents/skills/diataxis/scripts/generate_index.py +139 -0
  10. data/.rspec +3 -0
  11. data/.standard.yml +3 -0
  12. data/AGENTS.md +120 -0
  13. data/CHANGELOG.md +5 -0
  14. data/Dockerfile.opensearch +4 -0
  15. data/Increase_Coverage.md +311 -0
  16. data/README.md +143 -0
  17. data/Rakefile +27 -0
  18. data/Steepfile +23 -0
  19. data/adrs/ADR-000-template.md +87 -0
  20. data/adrs/ADR-001-simpledelegator-for-client.md +138 -0
  21. data/adrs/ADR-002-facade-pattern-for-index.md +126 -0
  22. data/adrs/ADR-003-repository-pattern-for-models.md +148 -0
  23. data/adrs/ADR-004-integration-tests-no-mocking.md +91 -0
  24. data/adrs/ADR-005-exceptions-over-result-objects.md +107 -0
  25. data/adrs/ADR-006-ssl-on-by-default.md +95 -0
  26. data/adrs/ADR-007-selective-sugar-surface.md +118 -0
  27. data/adrs/ADR-008-integration-test-design.md +178 -0
  28. data/compose.yml +2 -0
  29. data/compose_opensearch.yml +31 -0
  30. data/docs/HOWTO.md +844 -0
  31. data/docs/REFERENCE.md +725 -0
  32. data/docs/TUTORIAL.md +327 -0
  33. data/docs/alias-api-design-notes.md +119 -0
  34. data/lib/opensearch/sugar/client.rb +300 -0
  35. data/lib/opensearch/sugar/index/include/utilities.rb +6 -0
  36. data/lib/opensearch/sugar/index.rb +339 -0
  37. data/lib/opensearch/sugar/models.rb +209 -0
  38. data/lib/opensearch/sugar/version.rb +8 -0
  39. data/lib/opensearch/sugar.rb +61 -0
  40. data/old_docs/DELEGATED_METHODS_ANALYSIS.md +361 -0
  41. data/old_docs/EXPLANATION.md +685 -0
  42. data/old_docs/README.md +155 -0
  43. data/old_docs/docs/CLI-PROPOSAL.md +257 -0
  44. data/old_docs/docs/HOWTO.md +798 -0
  45. data/old_docs/docs/REFERENCE.md +901 -0
  46. data/old_docs/docs/TUTORIAL.md +493 -0
  47. data/sig/opensearch/sugar.rbs +162 -0
  48. metadata +240 -0
data/docs/REFERENCE.md ADDED
@@ -0,0 +1,725 @@
1
+ # API Reference
2
+
3
+ Complete reference for the opensearch-sugar public API.
4
+ Create by various AI agents.
5
+
6
+ ---
7
+
8
+ ## `OpenSearch::Sugar::Client`
9
+
10
+ A `SimpleDelegator` wrapper around `OpenSearch::Client` that adds index management
11
+ helpers and object-oriented access to indexes and ML models.
12
+
13
+ All methods of the underlying `OpenSearch::Client` are available directly — search,
14
+ bulk, indices, cluster, and so on. Sugar-specific methods are documented below.
15
+
16
+ ### Constructor
17
+
18
+ ```ruby
19
+ OpenSearch::Sugar::Client.new(host: url, **kwargs)
20
+ ```
21
+
22
+ **Keyword arguments**
23
+
24
+ | Name | Type | Default | Description |
25
+ |------|------|---------|-------------|
26
+ | `host` | String | `OPENSEARCH_URL` → `OPENSEARCH_HOST` → `"https://localhost:9000"` | Cluster base URL |
27
+ | `**kwargs` | Hash | — | Forwarded to `OpenSearch::Client.new` |
28
+
29
+ **Environment variable fallbacks** (all optional)
30
+
31
+ | Variable | Used for |
32
+ |----------|----------|
33
+ | `OPENSEARCH_URL` | `host` |
34
+ | `OPENSEARCH_HOST` | `host` (lower priority) |
35
+ | `OPENSEARCH_USER` | HTTP basic auth user (default: `"admin"`) |
36
+ | `OPENSEARCH_PASSWORD` | HTTP basic auth password |
37
+ | `OPENSEARCH_INITIAL_ADMIN_PASSWORD` | HTTP basic auth password (lower priority) |
38
+
39
+ **Default connection options applied automatically**
40
+
41
+ - `retry_on_failure: 5`
42
+ - `request_timeout: 5` seconds
43
+ - `log: true`
44
+ - `transport_options: { ssl: { verify: false } }`
45
+
46
+ Explicit `kwargs` take precedence over these defaults.
47
+
48
+ **Example**
49
+
50
+ ```ruby
51
+ client = OpenSearch::Sugar::Client.new
52
+ client = OpenSearch::Sugar::Client.new(host: "https://search.example.com:9200")
53
+ client = OpenSearch::Sugar::Client.new(host: "https://localhost:9200", log: false)
54
+ ```
55
+
56
+ ---
57
+
58
+ ### `Client#[]`
59
+
60
+ ```ruby
61
+ client[index_name] → OpenSearch::Sugar::Index
62
+ ```
63
+
64
+ Opens an existing index by name.
65
+
66
+ **Raises** `ArgumentError` if the index does not exist.
67
+
68
+ ```ruby
69
+ index = client["products"]
70
+ ```
71
+
72
+ ---
73
+
74
+ ### `Client#open_or_create_index`
75
+
76
+ ```ruby
77
+ client.open_or_create_index(index_name) → OpenSearch::Sugar::Index
78
+ ```
79
+
80
+ Opens the index if it exists; creates it (with KNN enabled) if it does not.
81
+
82
+ ```ruby
83
+ index = client.open_or_create_index("products")
84
+ ```
85
+
86
+ ---
87
+
88
+ ### `Client#has_index?`
89
+
90
+ ```ruby
91
+ client.has_index?(name) → Boolean
92
+ ```
93
+
94
+ Returns `true` if the named index exists in the cluster.
95
+
96
+ ```ruby
97
+ client.has_index?("products") #=> true
98
+ ```
99
+
100
+ ---
101
+
102
+ ### `Client#index_names`
103
+
104
+ ```ruby
105
+ client.index_names → Array<String>
106
+ ```
107
+
108
+ Returns the names of all user-created indexes. System indexes (names beginning with `.`) are excluded.
109
+
110
+ ```ruby
111
+ client.index_names #=> ["products", "orders"]
112
+ ```
113
+
114
+ ---
115
+
116
+ ### `Client#delete_index!`
117
+
118
+ ```ruby
119
+ client.delete_index!(index_name) → Hash
120
+ ```
121
+
122
+ Permanently deletes the named index.
123
+
124
+ **Raises** `OpenSearch::Transport::Transport::Errors::NotFound` if the index does not exist.
125
+
126
+ ```ruby
127
+ client.delete_index!("products")
128
+ ```
129
+
130
+ ---
131
+
132
+ ### `Client#update_settings`
133
+
134
+ ```ruby
135
+ client.update_settings(settings, index_name) → Hash
136
+ ```
137
+
138
+ Applies settings to an existing index. Automatically closes the index, applies the
139
+ settings, then reopens it.
140
+
141
+ `settings` may include or omit a top-level `:settings` key.
142
+
143
+ **Raises** `OpenSearch::Sugar::Error` if the update fails (the index is reopened before raising).
144
+
145
+ ```ruby
146
+ client.update_settings(
147
+ { settings: { analysis: { analyzer: { my: { type: "standard" } } } } },
148
+ "products"
149
+ )
150
+ ```
151
+
152
+ ---
153
+
154
+ ### `Client#update_mappings`
155
+
156
+ ```ruby
157
+ client.update_mappings(mappings, index_name) → Hash
158
+ ```
159
+
160
+ Applies field mappings to an existing index. Automatically closes the index, applies
161
+ the mappings, then reopens it.
162
+
163
+ `mappings` may include or omit a top-level `:mappings` key.
164
+
165
+ **Raises** `OpenSearch::Sugar::Error` if the update fails (the index is reopened before raising).
166
+
167
+ ```ruby
168
+ client.update_mappings(
169
+ { mappings: { properties: { title: { type: "text" } } } },
170
+ "products"
171
+ )
172
+ ```
173
+
174
+ ---
175
+
176
+ ### `Client#set_log_level`
177
+
178
+ ```ruby
179
+ client.set_log_level(logger: "logger._root", level: "warn") → Hash
180
+ ```
181
+
182
+ Writes a persistent cluster setting that controls the log level of the named logger.
183
+ The change survives cluster restarts.
184
+
185
+ **Parameters**
186
+
187
+ | Name | Type | Default | Description |
188
+ |------|------|---------|-------------|
189
+ | `logger` | String | `"logger._root"` | Logger name as understood by OpenSearch |
190
+ | `level` | String | `"warn"` | One of `"trace"`, `"debug"`, `"info"`, `"warn"`, `"error"` |
191
+
192
+ ```ruby
193
+ client.set_log_level(level: "error")
194
+ client.set_log_level(logger: "logger.org.opensearch.discovery", level: "debug")
195
+ ```
196
+
197
+ ---
198
+
199
+ ### `Client#models`
200
+
201
+ ```ruby
202
+ client.models → OpenSearch::Sugar::Models
203
+ ```
204
+
205
+ Returns the `Models` instance for this client. See [Models](#opensearchsugarmodels).
206
+
207
+ ---
208
+
209
+ ### `Client#raw_client`
210
+
211
+ ```ruby
212
+ client.raw_client → OpenSearch::Client
213
+ ```
214
+
215
+ Returns the unwrapped underlying `OpenSearch::Client` instance.
216
+
217
+ ---
218
+
219
+ ## `OpenSearch::Sugar::Index`
220
+
221
+ Represents a single OpenSearch index. Do not call `new` directly — obtain instances
222
+ via `Client#[]`, `Client#open_or_create_index`, `Index.open`, or `Index.create`.
223
+
224
+ ---
225
+
226
+ ### `Index.open` (class method)
227
+
228
+ ```ruby
229
+ OpenSearch::Sugar::Index.open(client:, name:) → Index
230
+ ```
231
+
232
+ Opens an existing index.
233
+
234
+ **Raises** `ArgumentError` if the index does not exist.
235
+
236
+ ```ruby
237
+ index = OpenSearch::Sugar::Index.open(client: client, name: "products")
238
+ ```
239
+
240
+ ---
241
+
242
+ ### `Index.create` (class method)
243
+
244
+ ```ruby
245
+ OpenSearch::Sugar::Index.create(client:, name:, knn: true) → Index
246
+ ```
247
+
248
+ Creates a new index.
249
+
250
+ **Parameters**
251
+
252
+ | Name | Type | Default | Description |
253
+ |------|------|---------|-------------|
254
+ | `client` | Client | — | Required |
255
+ | `name` | String | — | Required |
256
+ | `knn` | Boolean | `true` | Enable k-nearest-neighbor vector search on this index |
257
+
258
+ **Raises** `ArgumentError` if an index with the given name already exists.
259
+
260
+ ```ruby
261
+ index = OpenSearch::Sugar::Index.create(client: client, name: "products", knn: false)
262
+ ```
263
+
264
+ ---
265
+
266
+ ### `Index#name`
267
+
268
+ ```ruby
269
+ index.name → String
270
+ ```
271
+
272
+ The name of this index.
273
+
274
+ ---
275
+
276
+ ### `Index#count`
277
+
278
+ ```ruby
279
+ index.count → Integer
280
+ ```
281
+
282
+ Returns the number of documents in the index.
283
+
284
+ ```ruby
285
+ index.count #=> 1500
286
+ ```
287
+
288
+ ---
289
+
290
+ ### `Index#refresh`
291
+
292
+ ```ruby
293
+ index.refresh → Hash
294
+ ```
295
+
296
+ Forces a refresh, making all recently indexed documents immediately visible to search
297
+ queries. Use after `index_document` or `index_jsonl_file` in tests and scripts where
298
+ you query immediately after indexing.
299
+
300
+ ---
301
+
302
+ ### `Index#index_document`
303
+
304
+ ```ruby
305
+ index.index_document(doc, id) → Hash
306
+ ```
307
+
308
+ Indexes a single document. Issues one HTTP request per call — not suitable for large
309
+ batches. For bulk loading use the raw `client.bulk` API.
310
+
311
+ **Parameters**
312
+
313
+ | Name | Type | Description |
314
+ |------|------|-------------|
315
+ | `doc` | Hash | Document body |
316
+ | `id` | String | Document ID (`_id` in OpenSearch) |
317
+
318
+ ```ruby
319
+ index.index_document({ title: "Dune", author: "Frank Herbert" }, "isbn-0441013597")
320
+ ```
321
+
322
+ ---
323
+
324
+ ### `Index#index_jsonl_file`
325
+
326
+ ```ruby
327
+ index.index_jsonl_file(source, id_field:) → void
328
+ ```
329
+
330
+ Indexes all documents from a JSONL (newline-delimited JSON) source. Each line must be
331
+ a valid JSON object. The value of `id_field` in each document is used as `_id`.
332
+
333
+ `source` may be a file path `String` or any IO-like object (e.g. `File`, `StringIO`).
334
+
335
+ Issues one HTTP request per line — not suitable for very large files. For bulk loading
336
+ use the raw `client.bulk` API.
337
+
338
+ **Raises** `ArgumentError` if a line does not contain the specified `id_field`.
339
+
340
+ ```ruby
341
+ index.index_jsonl_file("/data/products.jsonl", id_field: :sku)
342
+ index.index_jsonl_file(StringIO.new(jsonl_string), id_field: :id)
343
+ ```
344
+
345
+ ---
346
+
347
+ ### `Index#delete_by_id`
348
+
349
+ ```ruby
350
+ index.delete_by_id(id) → Hash
351
+ ```
352
+
353
+ Deletes the document with the given ID.
354
+
355
+ **Raises** `ArgumentError` if `id` is `nil` or empty.
356
+
357
+ ```ruby
358
+ index.delete_by_id("isbn-0441013597")
359
+ ```
360
+
361
+ ---
362
+
363
+ ### `Index#clear!`
364
+
365
+ ```ruby
366
+ index.clear! → Integer
367
+ ```
368
+
369
+ Deletes all documents from the index using `delete_by_query`. Returns the number of
370
+ documents deleted. The index itself is preserved.
371
+
372
+ ```ruby
373
+ deleted = index.clear! #=> 1500
374
+ ```
375
+
376
+ ---
377
+
378
+ ### `Index#delete!`
379
+
380
+ ```ruby
381
+ index.delete! → Hash
382
+ ```
383
+
384
+ Permanently deletes the entire index and all its documents from the cluster.
385
+
386
+ ```ruby
387
+ index.delete!
388
+ ```
389
+
390
+ ---
391
+
392
+ ### `Index#settings`
393
+
394
+ ```ruby
395
+ index.settings → Hash
396
+ ```
397
+
398
+ Returns the current settings for this index, keyed by index name.
399
+
400
+ ```ruby
401
+ index.settings
402
+ #=> { "products" => { "settings" => { "index" => { "number_of_shards" => "1", ... } } } }
403
+ ```
404
+
405
+ ---
406
+
407
+ ### `Index#update_settings`
408
+
409
+ ```ruby
410
+ index.update_settings(settings) → Hash
411
+ ```
412
+
413
+ Applies new settings. Delegates to `Client#update_settings`. Accepts a hash with or
414
+ without a top-level `:settings` key.
415
+
416
+ Automatically closes the index, applies settings, and reopens it.
417
+
418
+ **Raises** `OpenSearch::Sugar::Error` on failure.
419
+
420
+ ---
421
+
422
+ ### `Index#mappings`
423
+
424
+ ```ruby
425
+ index.mappings → Hash
426
+ ```
427
+
428
+ Returns the current field mappings for this index, keyed by index name.
429
+
430
+ ```ruby
431
+ index.mappings
432
+ #=> { "products" => { "mappings" => { "properties" => { "title" => { "type" => "text" } } } } }
433
+ ```
434
+
435
+ ---
436
+
437
+ ### `Index#update_mappings`
438
+
439
+ ```ruby
440
+ index.update_mappings(mappings) → Hash
441
+ ```
442
+
443
+ Applies new field mappings. Delegates to `Client#update_mappings`. Accepts a hash with
444
+ or without a top-level `:mappings` key.
445
+
446
+ Automatically closes the index, applies mappings, and reopens it.
447
+
448
+ **Raises** `OpenSearch::Sugar::Error` on failure.
449
+
450
+ ---
451
+
452
+ ### `Index#aliases`
453
+
454
+ ```ruby
455
+ index.aliases → Array<String>
456
+ ```
457
+
458
+ Returns the alias names for this index. Returns an empty array if no aliases exist.
459
+
460
+ ```ruby
461
+ index.aliases #=> ["products_current", "products_v2"]
462
+ ```
463
+
464
+ ---
465
+
466
+ ### `Index#create_alias`
467
+
468
+ ```ruby
469
+ index.create_alias(alias_name) → Array<String>
470
+ ```
471
+
472
+ Adds an alias to this index. Returns the complete updated list of aliases.
473
+
474
+ **Raises** `OpenSearch::Transport::Transport::Errors::BadRequest` if the alias already
475
+ exists on a different index.
476
+
477
+ ```ruby
478
+ index.create_alias("products_current") #=> ["products_current"]
479
+ ```
480
+
481
+ ---
482
+
483
+ ### `Index#analyzers` / `Index#all_available_analyzers`
484
+
485
+ ```ruby
486
+ index.analyzers → Array<String>
487
+ ```
488
+
489
+ Returns the names of all analyzers available for this index: those defined in the
490
+ index's own settings plus those defined at the cluster level. `analyzers` is an alias
491
+ for `all_available_analyzers`.
492
+
493
+ ```ruby
494
+ index.analyzers #=> ["my_english", "my_exact"]
495
+ ```
496
+
497
+ ---
498
+
499
+ ### `Index#test_analyzer_by_name`
500
+
501
+ ```ruby
502
+ index.test_analyzer_by_name(analyzer:, text:) → Array<String, Array<String>>
503
+ ```
504
+
505
+ Returns the tokens produced by the named analyzer when applied to `text`.
506
+
507
+ When multiple tokens share a position in the token stream (e.g. from a synonym filter),
508
+ they are grouped as a nested `Array` within the outer array.
509
+
510
+ **Raises** `ArgumentError` if the analyzer is not defined on this index.
511
+
512
+ Also available as `#analyze_text` (deprecated alias for backward compatibility).
513
+
514
+ ```ruby
515
+ index.test_analyzer_by_name(analyzer: "my_english", text: "Running fast")
516
+ #=> ["run", "fast"]
517
+
518
+ # With synonyms at the same position:
519
+ #=> ["quick", ["fast", "rapid"], "fox"]
520
+ ```
521
+
522
+ ---
523
+
524
+ ### `Index#test_analyzer_by_fieldname`
525
+
526
+ ```ruby
527
+ index.test_analyzer_by_fieldname(field:, text:) → Array<String, Array<String>>
528
+ ```
529
+
530
+ Looks up the analyzer configured for `field` in this index's mappings, then delegates
531
+ to `test_analyzer_by_name`. Produces the exact tokenization applied at index time.
532
+
533
+ **Raises** `ArgumentError` if `field` does not exist in the mappings.
534
+ **Raises** `ArgumentError` if `field` has no `analyzer` configured (e.g. `keyword` fields).
535
+
536
+ Also available as `#analyze_text_field` (deprecated alias for backward compatibility).
537
+
538
+ ```ruby
539
+ index.test_analyzer_by_fieldname(field: "title", text: "Running fast")
540
+ #=> ["run", "fast"]
541
+ ```
542
+
543
+ ---
544
+
545
+ ## `OpenSearch::Sugar::Models`
546
+
547
+ Manages ML models via the OpenSearch ML Commons plugin. Access via `client.models`.
548
+
549
+ ---
550
+
551
+ ### `Models#register` / `Models#deploy`
552
+
553
+ ```ruby
554
+ client.models.register(name:, version:, format: "TORCH_SCRIPT") → ML_INFO | nil
555
+ ```
556
+
557
+ Registers and deploys a pre-trained model. Idempotent — returns the existing model if
558
+ one matching `name` is already registered.
559
+
560
+ Polls the task status every 5 seconds until deployment completes or fails.
561
+
562
+ **Parameters**
563
+
564
+ | Name | Type | Default | Description |
565
+ |------|------|---------|-------------|
566
+ | `name` | String | — | Model name (e.g. `"all-MiniLM-L6-v2"`) |
567
+ | `version` | String | — | Version string (e.g. `"1.0.0"`) |
568
+ | `format` | String | `"TORCH_SCRIPT"` | Model format |
569
+
570
+ **Returns** an `ML_INFO` struct, or `nil` if the lookup after registration fails.
571
+
572
+ **Raises** `RuntimeError` if the registration task reports a `FAILED` state.
573
+
574
+ `deploy` is an alias for `register`.
575
+
576
+ ```ruby
577
+ model = client.models.register(name: "all-MiniLM-L6-v2", version: "1.0.0")
578
+ puts model.id
579
+ ```
580
+
581
+ ---
582
+
583
+ ### `Models#[]`
584
+
585
+ ```ruby
586
+ client.models[id_or_name] → ML_INFO | nil
587
+ ```
588
+
589
+ Looks up a deployed model by exact name, exact ID, or case-insensitive partial name.
590
+ When multiple partial matches exist, returns the one with the highest version.
591
+
592
+ Returns `nil` if no match is found.
593
+
594
+ ```ruby
595
+ client.models["all-MiniLM-L6-v2"] # exact name
596
+ client.models["abc123xyz"] # exact ID
597
+ client.models["MiniLM"] # partial, case-insensitive
598
+ ```
599
+
600
+ ---
601
+
602
+ ### `Models#list`
603
+
604
+ ```ruby
605
+ client.models.list → Array<ML_INFO>
606
+ ```
607
+
608
+ Returns all deployed models as an array of `ML_INFO` structs.
609
+
610
+ ```ruby
611
+ client.models.list.each { |m| puts "#{m.name} v#{m.version} (#{m.id})" }
612
+ ```
613
+
614
+ ---
615
+
616
+ ### `Models#raw_list`
617
+
618
+ ```ruby
619
+ client.models.raw_list → Hash
620
+ ```
621
+
622
+ Returns the raw OpenSearch response from the ML models search endpoint. Prefer `list`
623
+ or `[]` for normal use.
624
+
625
+ ---
626
+
627
+ ### `Models#undeploy!`
628
+
629
+ ```ruby
630
+ client.models.undeploy!(name_or_id) → Hash
631
+ ```
632
+
633
+ Unloads the model from cluster memory without deleting its registration.
634
+
635
+ **Raises** `NoMethodError` if no model matching `name_or_id` is found.
636
+
637
+ ```ruby
638
+ client.models.undeploy!("all-MiniLM-L6-v2")
639
+ ```
640
+
641
+ ---
642
+
643
+ ### `Models#delete!`
644
+
645
+ ```ruby
646
+ client.models.delete!(name_or_id) → Hash
647
+ ```
648
+
649
+ Undeploys and permanently deletes the model.
650
+
651
+ **Raises** `NoMethodError` if no model matching `name_or_id` is found.
652
+
653
+ ```ruby
654
+ client.models.delete!("all-MiniLM-L6-v2")
655
+ ```
656
+
657
+ ---
658
+
659
+ ### `Models#create_pipeline`
660
+
661
+ ```ruby
662
+ client.models.create_pipeline(name:, model:, description:, field_map:) → Hash
663
+ ```
664
+
665
+ Creates a text-embedding ingest pipeline backed by a deployed ML model. Uses the
666
+ ML Commons `text_embedding` processor plus `copy` processors to move the resulting
667
+ `.knn` vectors to the intended target fields.
668
+
669
+ **Parameters**
670
+
671
+ | Name | Type | Description |
672
+ |------|------|-------------|
673
+ | `name` | String | Pipeline name |
674
+ | `model` | String | Model name, ID, or partial name accepted by `#[]` |
675
+ | `description` | String | Human-readable description |
676
+ | `field_map` | Hash{String => String} | Source text field → target vector field |
677
+
678
+ **Raises** `RuntimeError` if no model matching `model` is found.
679
+
680
+ ```ruby
681
+ client.models.create_pipeline(
682
+ name: "book-embeddings",
683
+ model: "all-MiniLM-L6-v2",
684
+ description: "Generate title embeddings",
685
+ field_map: { "title" => "title_embedding" }
686
+ )
687
+ ```
688
+
689
+ ---
690
+
691
+ ### `Models#delete_pipeline!`
692
+
693
+ ```ruby
694
+ client.models.delete_pipeline!(pipeline_name) → Hash
695
+ ```
696
+
697
+ Deletes an ingest pipeline by name.
698
+
699
+ ```ruby
700
+ client.models.delete_pipeline!("book-embeddings")
701
+ ```
702
+
703
+ ---
704
+
705
+ ## `OpenSearch::Sugar::Models::ML_INFO`
706
+
707
+ A `Struct` with three read-only members representing a deployed ML model.
708
+
709
+ | Member | Type | Description |
710
+ |--------|------|-------------|
711
+ | `name` | String | Model name as registered |
712
+ | `version` | String | Version string |
713
+ | `id` | String | Internal OpenSearch model ID used in API calls |
714
+
715
+ ---
716
+
717
+ ## Errors
718
+
719
+ | Class | Superclass | When raised |
720
+ |-------|-----------|-------------|
721
+ | `OpenSearch::Sugar::Error` | `StandardError` | Settings or mappings update fails |
722
+ | `ArgumentError` | `StandardError` | Invalid argument (missing index, bad analyzer, nil ID, etc.) |
723
+ | `OpenSearch::Transport::Transport::Errors::NotFound` | — | Index not found on `delete_index!` |
724
+ | `OpenSearch::Transport::Transport::Errors::BadRequest` | — | Invalid request to OpenSearch (e.g. duplicate alias) |
725
+ | `RuntimeError` | `StandardError` | ML model registration fails or model not found |