Generating embeddings for arrays of objects

This tutorial illustrates how to generate embeddings for arrays of objects.

Replace the placeholders beginning with the prefix your_ with your own values.

Step 1: Register an embedding model

For this tutorial, you will use the Amazon Bedrock Titan Embedding model.

First, follow the Amazon Bedrock Titan blueprint example to register and deploy the model.

Test the model, providing the model ID:

  1. POST /_plugins/_ml/models/your_embedding_model_id/_predict
  2. {
  3. "parameters": {
  4. "inputText": "hello world"
  5. }
  6. }

copy

The response contains inference results:

  1. {
  2. "inference_results": [
  3. {
  4. "output": [
  5. {
  6. "name": "sentence_embedding",
  7. "data_type": "FLOAT32",
  8. "shape": [ 1536 ],
  9. "data": [0.7265625, -0.0703125, 0.34765625, ...]
  10. }
  11. ],
  12. "status_code": 200
  13. }
  14. ]
  15. }

Step 2: Create an ingest pipeline

Follow the next set of steps to create an ingest pipeline for generating embeddings.

Step 2.1: Create a k-NN index

First, create a k-NN index:

  1. PUT my_books
  2. {
  3. "settings" : {
  4. "index.knn" : "true",
  5. "default_pipeline": "bedrock_embedding_foreach_pipeline"
  6. },
  7. "mappings": {
  8. "properties": {
  9. "books": {
  10. "type": "nested",
  11. "properties": {
  12. "title_embedding": {
  13. "type": "knn_vector",
  14. "dimension": 1536
  15. },
  16. "title": {
  17. "type": "text"
  18. },
  19. "description": {
  20. "type": "text"
  21. }
  22. }
  23. }
  24. }
  25. }
  26. }

copy

Step 2.2: Create an ingest pipeline

Then create an inner ingest pipeline to generate an embedding for one array element.

This pipeline contains three processors:

  • set processor: The text_embedding processor is unable to identify the _ingest._value.title field. You must copy _ingest._value.title to a non-existing temporary field so that the text_embedding processor can process it.
  • text_embedding processor: Converts the value of the temporary field to an embedding.
  • remove processor: Removes the temporary field.

To create such a pipeline, send the following request:

  1. PUT _ingest/pipeline/bedrock_embedding_pipeline
  2. {
  3. "processors": [
  4. {
  5. "set": {
  6. "field": "title_tmp",
  7. "value": ""
  8. }
  9. },
  10. {
  11. "text_embedding": {
  12. "model_id": your_embedding_model_id,
  13. "field_map": {
  14. "title_tmp": "_ingest._value.title_embedding"
  15. }
  16. }
  17. },
  18. {
  19. "remove": {
  20. "field": "title_tmp"
  21. }
  22. }
  23. ]
  24. }

copy

Create an ingest pipeline with a foreach processor that will apply the bedrock_embedding_pipeline to each element of the books array:

  1. PUT _ingest/pipeline/bedrock_embedding_foreach_pipeline
  2. {
  3. "description": "Test nested embeddings",
  4. "processors": [
  5. {
  6. "foreach": {
  7. "field": "books",
  8. "processor": {
  9. "pipeline": {
  10. "name": "bedrock_embedding_pipeline"
  11. }
  12. },
  13. "ignore_failure": true
  14. }
  15. }
  16. ]
  17. }

copy

Step 2.3: Simulate the pipeline

First, you’ll test the pipeline on an array that contains two book objects, both with a title field:

  1. POST _ingest/pipeline/bedrock_embedding_foreach_pipeline/_simulate
  2. {
  3. "docs": [
  4. {
  5. "_index": "my_books",
  6. "_id": "1",
  7. "_source": {
  8. "books": [
  9. {
  10. "title": "first book",
  11. "description": "This is first book"
  12. },
  13. {
  14. "title": "second book",
  15. "description": "This is second book"
  16. }
  17. ]
  18. }
  19. }
  20. ]
  21. }

copy

The response contains generated embeddings for both objects in their title_embedding fields:

  1. {
  2. "docs": [
  3. {
  4. "doc": {
  5. "_index": "my_books",
  6. "_id": "1",
  7. "_source": {
  8. "books": [
  9. {
  10. "title": "first book",
  11. "title_embedding": [-1.1015625, 0.65234375, 0.7578125, ...],
  12. "description": "This is first book"
  13. },
  14. {
  15. "title": "second book",
  16. "title_embedding": [-0.65234375, 0.21679688, 0.7265625, ...],
  17. "description": "This is second book"
  18. }
  19. ]
  20. },
  21. "_ingest": {
  22. "_value": null,
  23. "timestamp": "2024-05-28T16:16:50.538929413Z"
  24. }
  25. }
  26. }
  27. ]
  28. }

Next, you’ll test the pipeline on an array that contains two book objects, one with a title field and one without:

  1. POST _ingest/pipeline/bedrock_embedding_foreach_pipeline/_simulate
  2. {
  3. "docs": [
  4. {
  5. "_index": "my_books",
  6. "_id": "1",
  7. "_source": {
  8. "books": [
  9. {
  10. "title": "first book",
  11. "description": "This is first book"
  12. },
  13. {
  14. "description": "This is second book"
  15. }
  16. ]
  17. }
  18. }
  19. ]
  20. }

copy

The response contains generated embeddings for the object that contains the title field:

  1. {
  2. "docs": [
  3. {
  4. "doc": {
  5. "_index": "my_books",
  6. "_id": "1",
  7. "_source": {
  8. "books": [
  9. {
  10. "title": "first book",
  11. "title_embedding": [-1.1015625, 0.65234375, 0.7578125, ...],
  12. "description": "This is first book"
  13. },
  14. {
  15. "description": "This is second book"
  16. }
  17. ]
  18. },
  19. "_ingest": {
  20. "_value": null,
  21. "timestamp": "2024-05-28T16:19:03.942644042Z"
  22. }
  23. }
  24. }
  25. ]
  26. }

Step 2.4: Test data ingestion

Ingest one document:

  1. PUT my_books/_doc/1
  2. {
  3. "books": [
  4. {
  5. "title": "first book",
  6. "description": "This is first book"
  7. },
  8. {
  9. "title": "second book",
  10. "description": "This is second book"
  11. }
  12. ]
  13. }

copy

Get the document:

  1. GET my_books/_doc/1

copy

The response contains the generated embeddings:

  1. {
  2. "_index": "my_books",
  3. "_id": "1",
  4. "_version": 1,
  5. "_seq_no": 0,
  6. "_primary_term": 1,
  7. "found": true,
  8. "_source": {
  9. "books": [
  10. {
  11. "description": "This is first book",
  12. "title": "first book",
  13. "title_embedding": [-1.1015625, 0.65234375, 0.7578125, ...]
  14. },
  15. {
  16. "description": "This is second book",
  17. "title": "second book",
  18. "title_embedding": [-0.65234375, 0.21679688, 0.7265625, ...]
  19. }
  20. ]
  21. }
  22. }

You can also ingest several documents in bulk and test the generated embeddings by calling the Get Document API:

  1. POST _bulk
  2. { "index" : { "_index" : "my_books" } }
  3. { "books" : [{"title": "first book", "description": "This is first book"}, {"title": "second book", "description": "This is second book"}] }
  4. { "index" : { "_index" : "my_books" } }
  5. { "books" : [{"title": "third book", "description": "This is third book"}, {"description": "This is fourth book"}] }

copy