Spec-Zone.ru › Elasticsearch 8
›Elasticsearch Guide [8.17] ›Поиск данных ›Извлекатели

Примеры использования извлекателей

Добавление примеров данных

Для начала создадим индекс retrievers_example и добавим в него несколько документов. Мы установим number_of_shards=1 для наших примеров, чтобы обеспечить последовательное и воспроизводимое упорядочивание.

PUT retrievers_example
{
    "settings": {
        "number_of_shards": 1
    },
   "mappings": {
       "properties": {
           "vector": {
               "type": "dense_vector",
               "dims": 3,
               "similarity": "l2_norm",
               "index": true,
               "index_options": {
                    "type": "flat"
               }
           },
           "text": {
               "type": "text"
           },
           "year": {
               "type": "integer"
           },
           "topic": {
               "type": "keyword"
           }
       }
   }
}

POST /retrievers_example/_doc/1
{
 "vector": [0.23, 0.67, 0.89],
 "text": "Large language models are revolutionizing information retrieval by boosting search precision, deepening contextual understanding, and reshaping user experiences in data-rich environments.",
 "year": 2024,
 "topic": ["llm", "ai", "information_retrieval"]
}

POST /retrievers_example/_doc/2
{
 "vector": [0.12, 0.56, 0.78],
 "text": "Artificial intelligence is transforming medicine, from advancing diagnostics and tailoring treatment plans to empowering predictive patient care for improved health outcomes.",
 "year": 2023,
 "topic": ["ai", "medicine"]
}

POST /retrievers_example/_doc/3
{
 "vector": [0.45, 0.32, 0.91],
  "text": "AI is redefining security by enabling advanced threat detection, proactive risk analysis, and dynamic defenses against increasingly sophisticated cyber threats.",
 "year": 2024,
 "topic": ["ai", "security"]
}

POST /retrievers_example/_doc/4
{
 "vector": [0.34, 0.21, 0.98],
 "text": "Elastic introduces Elastic AI Assistant, the open, generative AI sidekick powered by ESRE to democratize cybersecurity and enable users of every skill level.",
 "year": 2023,
 "topic": ["ai", "elastic", "assistant"]
}

POST /retrievers_example/_doc/5
{
 "vector": [0.11, 0.65, 0.47],
 "text": "Learn how to spin up a deployment of our hosted Elasticsearch Service and use Elastic Observability to gain deeper insight into the behavior of your applications and systems.",
 "year": 2024,
 "topic": ["documentation", "observability", "elastic"]
}

POST /retrievers_example/_refresh

Теперь, когда документы готовы, давайте попробуем выполнить несколько запросов с использованием извлекателей.

Пример: Объединение запроса и kNN с RRF

Сначала рассмотрим, как объединить два разных типа запросов: запрос kNN и запрос query_string. Хотя эти запросы могут генерировать оценки в различных диапазонах, мы можем использовать Reciprocal Rank Fusion (rrf) для объединения результатов и создания объединённого списка результатов.

Для реализации этого в рамках фреймворка извлекателей мы начнём с основного элемента: нашего извлекателя rrf. Этот извлекатель работает на основе двух других извлекателей: извлекателя knn и извлекателя standard. Наша структура запроса будет выглядеть так:

resp = client.search(
    index="retrievers_example",
    retriever={
        "rrf": {
            "retrievers": [
                {
                    "standard": {
                        "query": {
                            "query_string": {
                                "query": "(information retrieval) OR (artificial intelligence)",
                                "default_field": "text"
                            }
                        }
                    }
                },
                {
                    "knn": {
                        "field": "vector",
                        "query_vector": [
                            0.23,
                            0.67,
                            0.89
                        ],
                        "k": 3,
                        "num_candidates": 5
                    }
                }
            ],
            "rank_window_size": 10,
            "rank_constant": 1
        }
    },
    source=False,
)
print(resp)
const response = await client.search({
  index: "retrievers_example",
  retriever: {
    rrf: {
      retrievers: [
        {
          standard: {
            query: {
              query_string: {
                query: "(information retrieval) OR (artificial intelligence)",
                default_field: "text",
              },
            },
          },
        },
        {
          knn: {
            field: "vector",
            query_vector: [0.23, 0.67, 0.89],
            k: 3,
            num_candidates: 5,
          },
        },
      ],
      rank_window_size: 10,
      rank_constant: 1,
    },
  },
  _source: false,
});
console.log(response);
GET /retrievers_example/_search
{
    "retriever": {
        "rrf": {
            "retrievers": [
                {
                    "standard": {
                        "query": {
                            "query_string": {
                                "query": "(information retrieval) OR (artificial intelligence)",
                                "default_field": "text"
                            }
                        }
                    }
                },
                {
                    "knn": {
                        "field": "vector",
                        "query_vector": [
                            0.23,
                            0.67,
                            0.89
                        ],
                        "k": 3,
                        "num_candidates": 5
                    }
                }
            ],
            "rank_window_size": 10,
            "rank_constant": 1
        }
    },
    "_source": false
}

Это возвращает следующий ответ на основе итогового rrf-счета для каждого результата.

Пример ответа
{
    "took": 42,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 3,
            "relation": "eq"
        },
        "max_score": 0.8333334,
        "hits": [
            {
                "_index": "retrievers_example",
                "_id": "1",
                "_score": 0.8333334
            },
            {
                "_index": "retrievers_example",
                "_id": "2",
                "_score": 0.8333334
            },
            {
                "_index": "retrievers_example",
                "_id": "3",
                "_score": 0.25
            }
        ]
    }
}

Пример: Группировка результатов по году с collapse

В нашем наборе результатов есть много документов с одинаковым значением поля year. Мы можем исправить это, используя параметр collapse с нашим извлекателем. Это, как и стандартная функция сжатия, позволяет группировать результаты по любому полю и возвращает только документ с наивысшим рейтингом из каждой группы. В этом примере мы будем сжимать результаты по полю year.

resp = client.search(
    index="retrievers_example",
    retriever={
        "rrf": {
            "retrievers": [
                {
                    "standard": {
                        "query": {
                            "query_string": {
                                "query": "(information retrieval) OR (artificial intelligence)",
                                "default_field": "text"
                            }
                        }
                    }
                },
                {
                    "knn": {
                        "field": "vector",
                        "query_vector": [
                            0.23,
                            0.67,
                            0.89
                        ],
                        "k": 3,
                        "num_candidates": 5
                    }
                }
            ],
            "rank_window_size": 10,
            "rank_constant": 1
        }
    },
    collapse={
        "field": "year",
        "inner_hits": {
            "name": "topic related documents",
            "_source": [
                "year"
            ]
        }
    },
    source=False,
)
print(resp)
const response = await client.search({
  index: "retrievers_example",
  retriever: {
    rrf: {
      retrievers: [
        {
          standard: {
            query: {
              query_string: {
                query: "(information retrieval) OR (artificial intelligence)",
                default_field: "text",
              },
            },
          },
        },
        {
          knn: {
            field: "vector",
            query_vector: [0.23, 0.67, 0.89],
            k: 3,
            num_candidates: 5,
          },
        },
      ],
      rank_window_size: 10,
      rank_constant: 1,
    },
  },
  collapse: {
    field: "year",
    inner_hits: {
      name: "topic related documents",
      _source: ["year"],
    },
  },
  _source: false,
});
console.log(response);
GET /retrievers_example/_search
{
    "retriever": {
        "rrf": {
            "retrievers": [
                {
                    "standard": {
                        "query": {
                            "query_string": {
                                "query": "(information retrieval) OR (artificial intelligence)",
                                "default_field": "text"
                            }
                        }
                    }
                },
                {
                    "knn": {
                        "field": "vector",
                        "query_vector": [
                            0.23,
                            0.67,
                            0.89
                        ],
                        "k": 3,
                        "num_candidates": 5
                    }
                }
            ],
            "rank_window_size": 10,
            "rank_constant": 1
        }
    },
    "collapse": {
        "field": "year",
        "inner_hits": {
            "name": "topic related documents",
            "_source": [
                "year"
            ]
        }
    },
    "_source": false
}

Это возвращает следующий ответ со сжатыми результатами.

Пример ответа
{
    "took": 42,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 3,
            "relation": "eq"
        },
        "max_score": 0.8333334,
        "hits": [
            {
                "_index": "retrievers_example",
                "_id": "1",
                "_score": 0.8333334,
                "fields": {
                    "year": [
                        2024
                    ]
                },
                "inner_hits": {
                    "topic related documents": {
                        "hits": {
                            "total": {
                                "value": 2,
                                "relation": "eq"
                            },
                            "max_score": 0.8333334,
                            "hits": [
                                {
                                    "_index": "retrievers_example",
                                    "_id": "1",
                                    "_score": 0.8333334,
                                    "_source": {
                                        "year": 2024
                                    }
                                },
                                {
                                    "_index": "retrievers_example",
                                    "_id": "3",
                                    "_score": 0.25,
                                    "_source": {
                                        "year": 2024
                                    }
                                }
                            ]
                        }
                    }
                }
            },
            {
                "_index": "retrievers_example",
                "_id": "2",
                "_score": 0.8333334,
                "fields": {
                    "year": [
                        2023
                    ]
                },
                "inner_hits": {
                    "topic related documents": {
                        "hits": {
                            "total": {
                                "value": 1,
                                "relation": "eq"
                            },
                            "max_score": 0.8333334,
                            "hits": [
                                {
                                    "_index": "retrievers_example",
                                    "_id": "2",
                                    "_score": 0.8333334,
                                    "_source": {
                                        "year": 2023
                                    }
                                }
                            ]
                        }
                    }
                }
            }
        ]
    }
}

Пример: Выделение результатов на основе вложенных под-извлекателей

Теперь выделение также доступно для совпадений вложенных под-извлекателей. Например, рассмотрим тот же извлекатель rrf, как и выше, с извлекателями knn и standard в качестве под-извлекателей. Мы можем указать секцию highlight, как определено в документации выделения, и вычислить выделения для лучших результатов.

resp = client.search(
    index="retrievers_example",
    retriever={
        "rrf": {
            "retrievers": [
                {
                    "standard": {
                        "query": {
                            "query_string": {
                                "query": "(information retrieval) OR (artificial intelligence)",
                                "default_field": "text"
                            }
                        }
                    }
                },
                {
                    "knn": {
                        "field": "vector",
                        "query_vector": [
                            0.23,
                            0.67,
                            0.89
                        ],
                        "k": 3,
                        "num_candidates": 5
                    }
                }
            ],
            "rank_window_size": 10,
            "rank_constant": 1
        }
    },
    highlight={
        "fields": {
            "text": {
                "fragment_size": 150,
                "number_of_fragments": 3
            }
        }
    },
    source=False,
)
print(resp)
const response = await client.search({
  index: "retrievers_example",
  retriever: {
    rrf: {
      retrievers: [
        {
          standard: {
            query: {
              query_string: {
                query: "(information retrieval) OR (artificial intelligence)",
                default_field: "text",
              },
            },
          },
        },
        {
          knn: {
            field: "vector",
            query_vector: [0.23, 0.67, 0.89],
            k: 3,
            num_candidates: 5,
          },
        },
      ],
      rank_window_size: 10,
      rank_constant: 1,
    },
  },
  highlight: {
    fields: {
      text: {
        fragment_size: 150,
        number_of_fragments: 3,
      },
    },
  },
  _source: false,
});
console.log(response);
GET /retrievers_example/_search
{
    "retriever": {
        "rrf": {
            "retrievers": [
                {
                    "standard": {
                        "query": {
                            "query_string": {
                                "query": "(information retrieval) OR (artificial intelligence)",
                                "default_field": "text"
                            }
                        }
                    }
                },
                {
                    "knn": {
                        "field": "vector",
                        "query_vector": [
                            0.23,
                            0.67,
                            0.89
                        ],
                        "k": 3,
                        "num_candidates": 5
                    }
                }
            ],
            "rank_window_size": 10,
            "rank_constant": 1
        }
    },
    "highlight": {
        "fields": {
            "text": {
                "fragment_size": 150,
                "number_of_fragments": 3
            }
        }
    },
    "_source": false
}

Это выделило бы поле text на основе совпадений, полученных извлекателем standard. Выделенные фрагменты затем будут включены в ответ, как обычно, т.е. под каждым результатом поиска.

Пример ответа
{
    "took": 42,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 3,
            "relation": "eq"
        },
        "max_score": 0.8333334,
        "hits": [
            {
                "_index": "retrievers_example",
                "_id": "1",
                "_score": 0.8333334,
                "highlight": {
                    "text": [
                        "Large language models are revolutionizing <em>information</em> <em>retrieval</em> by boosting search precision, deepening contextual understanding, and reshaping user experiences"
                    ]
                }
            },
            {
                "_index": "retrievers_example",
                "_id": "2",
                "_score": 0.8333334,
                "highlight": {
                    "text": [
                        "<em>Artificial</em> <em>intelligence</em> is transforming medicine, from advancing diagnostics and tailoring treatment plans to empowering predictive patient care for improved"
                    ]
                }
            },
            {
                "_index": "retrievers_example",
                "_id": "3",
                "_score": 0.25
            }
        ]
    }
}

Пример: Вычисление внутренних результатов из вложенных под-извлекателей

Мы также можем определить inner_hits для любого из под-извлекателей и распространить эти вычисления на составной извлекатель верхнего уровня. Например, давайте создадим новый индекс с полем knn, вложенным в поле nested_field, и добавим пару документов.

resp = client.indices.create(
    index="retrievers_example_nested",
    settings={
        "number_of_shards": 1
    },
    mappings={
        "properties": {
            "nested_field": {
                "type": "nested",
                "properties": {
                    "paragraph_id": {
                        "type": "keyword"
                    },
                    "nested_vector": {
                        "type": "dense_vector",
                        "dims": 3,
                        "similarity": "l2_norm",
                        "index": True,
                        "index_options": {
                            "type": "flat"
                        }
                    }
                }
            },
            "topic": {
                "type": "keyword"
            }
        }
    },
)
print(resp)

resp1 = client.index(
    index="retrievers_example_nested",
    id="1",
    document={
        "nested_field": [
            {
                "paragraph_id": "1a",
                "nested_vector": [
                    -1.12,
                    -0.59,
                    0.78
                ]
            },
            {
                "paragraph_id": "1b",
                "nested_vector": [
                    -0.12,
                    1.56,
                    0.42
                ]
            },
            {
                "paragraph_id": "1c",
                "nested_vector": [
                    1,
                    -1,
                    0
                ]
            }
        ],
        "topic": [
            "ai"
        ]
    },
)
print(resp1)

resp2 = client.index(
    index="retrievers_example_nested",
    id="2",
    document={
        "nested_field": [
            {
                "paragraph_id": "2a",
                "nested_vector": [
                    0.23,
                    1.24,
                    0.65
                ]
            }
        ],
        "topic": [
            "information_retrieval"
        ]
    },
)
print(resp2)

resp3 = client.index(
    index="retrievers_example_nested",
    id="3",
    document={
        "topic": [
            "ai"
        ]
    },
)
print(resp3)

resp4 = client.indices.refresh(
    index="retrievers_example_nested",
)
print(resp4)
const response = await client.indices.create({
  index: "retrievers_example_nested",
  settings: {
    number_of_shards: 1,
  },
  mappings: {
    properties: {
      nested_field: {
        type: "nested",
        properties: {
          paragraph_id: {
            type: "keyword",
          },
          nested_vector: {
            type: "dense_vector",
            dims: 3,
            similarity: "l2_norm",
            index: true,
            index_options: {
              type: "flat",
            },
          },
        },
      },
      topic: {
        type: "keyword",
      },
    },
  },
});
console.log(response);

const response1 = await client.index({
  index: "retrievers_example_nested",
  id: 1,
  document: {
    nested_field: [
      {
        paragraph_id: "1a",
        nested_vector: [-1.12, -0.59, 0.78],
      },
      {
        paragraph_id: "1b",
        nested_vector: [-0.12, 1.56, 0.42],
      },
      {
        paragraph_id: "1c",
        nested_vector: [1, -1, 0],
      },
    ],
    topic: ["ai"],
  },
});
console.log(response1);

const response2 = await client.index({
  index: "retrievers_example_nested",
  id: 2,
  document: {
    nested_field: [
      {
        paragraph_id: "2a",
        nested_vector: [0.23, 1.24, 0.65],
      },
    ],
    topic: ["information_retrieval"],
  },
});
console.log(response2);

const response3 = await client.index({
  index: "retrievers_example_nested",
  id: 3,
  document: {
    topic: ["ai"],
  },
});
console.log(response3);

const response4 = await client.indices.refresh({
  index: "retrievers_example_nested",
});
console.log(response4);
PUT retrievers_example_nested
{
    "settings": {
         "number_of_shards": 1
     },
    "mappings": {
        "properties": {
            "nested_field": {
                "type": "nested",
                "properties": {
                    "paragraph_id": {
                        "type": "keyword"
                    },
                    "nested_vector": {
                        "type": "dense_vector",
                        "dims": 3,
                        "similarity": "l2_norm",
                        "index": true,
                        "index_options": {
                            "type": "flat"
                        }
                    }
                }
            },
            "topic": {
                "type": "keyword"
            }
        }
    }
}

POST /retrievers_example_nested/_doc/1
{
    "nested_field": [
        {
            "paragraph_id": "1a",
            "nested_vector": [
                -1.12,
                -0.59,
                0.78
            ]
        },
        {
            "paragraph_id": "1b",
            "nested_vector": [
                -0.12,
                1.56,
                0.42
            ]
        },
        {
            "paragraph_id": "1c",
            "nested_vector": [
                1,
                -1,
                0
            ]
        }
    ],
    "topic": [
        "ai"
    ]
}

POST /retrievers_example_nested/_doc/2
{
    "nested_field": [
        {
            "paragraph_id": "2a",
            "nested_vector": [
                0.23,
                1.24,
                0.65
            ]
        }
    ],
    "topic": [
        "information_retrieval"
    ]
}

POST /retrievers_example_nested/_doc/3
{
    "topic": [
        "ai"
    ]
}

POST /retrievers_example_nested/_refresh

Теперь мы можем запустить запрос извлекателя rrf и также вычислить внутренние результаты для поля nested_field.nested_vector, на основе запроса knn.

resp = client.search(
    index="retrievers_example_nested",
    retriever={
        "rrf": {
            "retrievers": [
                {
                    "standard": {
                        "query": {
                            "nested": {
                                "path": "nested_field",
                                "inner_hits": {
                                    "name": "nested_vector",
                                    "_source": False,
                                    "fields": [
                                        "nested_field.paragraph_id"
                                    ]
                                },
                                "query": {
                                    "knn": {
                                        "field": "nested_field.nested_vector",
                                        "query_vector": [
                                            1,
                                            0,
                                            0.5
                                        ],
                                        "k": 10
                                    }
                                }
                            }
                        }
                    }
                },
                {
                    "standard": {
                        "query": {
                            "term": {
                                "topic": "ai"
                            }
                        }
                    }
                }
            ],
            "rank_window_size": 10,
            "rank_constant": 1
        }
    },
    source=[
        "topic"
    ],
)
print(resp)
const response = await client.search({
  index: "retrievers_example_nested",
  retriever: {
    rrf: {
      retrievers: [
        {
          standard: {
            query: {
              nested: {
                path: "nested_field",
                inner_hits: {
                  name: "nested_vector",
                  _source: false,
                  fields: ["nested_field.paragraph_id"],
                },
                query: {
                  knn: {
                    field: "nested_field.nested_vector",
                    query_vector: [1, 0, 0.5],
                    k: 10,
                  },
                },
              },
            },
          },
        },
        {
          standard: {
            query: {
              term: {
                topic: "ai",
              },
            },
          },
        },
      ],
      rank_window_size: 10,
      rank_constant: 1,
    },
  },
  _source: ["topic"],
});
console.log(response);
GET /retrievers_example_nested/_search
{
    "retriever": {
        "rrf": {
            "retrievers": [
                {
                    "standard": {
                        "query": {
                            "nested": {
                                "path": "nested_field",
                                "inner_hits": {
                                    "name": "nested_vector",
                                    "_source": false,
                                    "fields": [
                                        "nested_field.paragraph_id"
                                    ]
                                },
                                "query": {
                                    "knn": {
                                        "field": "nested_field.nested_vector",
                                        "query_vector": [
                                            1,
                                            0,
                                            0.5
                                        ],
                                        "k": 10
                                    }
                                }
                            }
                        }
                    }
                },
                {
                    "standard": {
                        "query": {
                            "term": {
                                "topic": "ai"
                            }
                        }
                    }
                }
            ],
            "rank_window_size": 10,
            "rank_constant": 1
        }
    },
    "_source": [
        "topic"
    ]
}

Это распространит inner_hits, определённое для запроса knn, на извлекатель rrf и вычислит внутренние результаты для лучших результатов rrf.

Пример ответа
{
    "took": 42,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 3,
            "relation": "eq"
        },
        "max_score": 1.0,
        "hits": [
            {
                "_index": "retrievers_example_nested",
                "_id": "1",
                "_score": 1.0,
                "_source": {
                    "topic": [
                        "ai"
                    ]
                },
                "inner_hits": {
                    "nested_vector": {
                        "hits": {
                            "total": {
                                "value": 3,
                                "relation": "eq"
                            },
                            "max_score": 0.44444445,
                            "hits": [
                                {
                                    "_index": "retrievers_example_nested",
                                    "_id": "1",
                                    "_nested": {
                                        "field": "nested_field",
                                        "offset": 2
                                    },
                                    "_score": 0.44444445,
                                    "fields": {
                                        "nested_field": [
                                            {
                                                "paragraph_id": [
                                                    "1c"
                                                ]
                                            }
                                        ]
                                    }
                                },
                                {
                                    "_index": "retrievers_example_nested",
                                    "_id": "1",
                                    "_nested": {
                                        "field": "nested_field",
                                        "offset": 1
                                    },
                                    "_score": 0.21301977,
                                    "fields": {
                                        "nested_field": [
                                            {
                                                "paragraph_id": [
                                                    "1b"
                                                ]
                                            }
                                        ]
                                    }
                                },
                                {
                                    "_index": "retrievers_example_nested",
                                    "_id": "1",
                                    "_nested": {
                                        "field": "nested_field",
                                        "offset": 0
                                    },
                                    "_score": 0.16889325,
                                    "fields": {
                                        "nested_field": [
                                            {
                                                "paragraph_id": [
                                                    "1a"
                                                ]
                                            }
                                        ]
                                    }
                                }
                            ]
                        }
                    }
                }
            },
            {
                "_index": "retrievers_example_nested",
                "_id": "2",
                "_score": 0.33333334,
                "_source": {
                    "topic": [
                        "information_retrieval"
                    ]
                },
                "inner_hits": {
                    "nested_vector": {
                        "hits": {
                            "total": {
                                "value": 1,
                                "relation": "eq"
                            },
                            "max_score": 0.31715825,
                            "hits": [
                                {
                                    "_index": "retrievers_example_nested",
                                    "_id": "2",
                                    "_nested": {
                                        "field": "nested_field",
                                        "offset": 0
                                    },
                                    "_score": 0.31715825,
                                    "fields": {
                                        "nested_field": [
                                            {
                                                "paragraph_id": [
                                                    "2a"
                                                ]
                                            }
                                        ]
                                    }
                                }
                            ]
                        }
                    }
                }
            },
            {
                "_index": "retrievers_example_nested",
                "_id": "3",
                "_score": 0.33333334,
                "_source": {
                    "topic": [
                        "ai"
                    ]
                },
                "inner_hits": {
                    "nested_vector": {
                        "hits": {
                            "total": {
                                "value": 0,
                                "relation": "eq"
                            },
                            "max_score": null,
                            "hits": []
                        }
                    }
                }
            }
        ]
    }
}

Примечание: если используется более одного inner_hits, нам необходимо предоставить пользовательские имена для каждого inner_hits, чтобы они были уникальными для всех извлекателей в запросе.

Пример: Объединение RRF с агрегациями

Извлекатели поддерживают как композицию, так и большинство стандартных функций _search. Например, мы можем вычислить агрегации с извлекателем rrf. При использовании составного извлекателя агрегации вычисляются на основе вложенных извлекателей. В следующем примере агрегация terms для поля topic будет включать все результаты, а не только лучшие результаты rank_window_size, от двух вложенных извлекателей, т.е. все документы, у которых поле year больше 2023, и у которых поле topic соответствует термину elastic.

resp = client.search(
    index="retrievers_example",
    retriever={
        "rrf": {
            "retrievers": [
                {
                    "standard": {
                        "query": {
                            "range": {
                                "year": {
                                    "gt": 2023
                                }
                            }
                        }
                    }
                },
                {
                    "standard": {
                        "query": {
                            "term": {
                                "topic": "elastic"
                            }
                        }
                    }
                }
            ],
            "rank_window_size": 10,
            "rank_constant": 1
        }
    },
    source=False,
    aggs={
        "topics": {
            "terms": {
                "field": "topic"
            }
        }
    },
)
print(resp)
const response = await client.search({
  index: "retrievers_example",
  retriever: {
    rrf: {
      retrievers: [
        {
          standard: {
            query: {
              range: {
                year: {
                  gt: 2023,
                },
              },
            },
          },
        },
        {
          standard: {
            query: {
              term: {
                topic: "elastic",
              },
            },
          },
        },
      ],
      rank_window_size: 10,
      rank_constant: 1,
    },
  },
  _source: false,
  aggs: {
    topics: {
      terms: {
        field: "topic",
      },
    },
  },
});
console.log(response);
GET retrievers_example/_search
{
    "retriever": {
        "rrf": {
            "retrievers": [
                {
                    "standard": {
                        "query": {
                            "range": {
                                "year": {
                                    "gt": 2023
                                }
                            }
                        }
                    }
                },
                {
                    "standard": {
                        "query": {
                            "term": {
                                "topic": "elastic"
                            }
                        }
                    }
                }
            ],
            "rank_window_size": 10,
            "rank_constant": 1
        }
    },
    "_source": false,
    "aggs": {
        "topics": {
            "terms": {
                "field": "topic"
            }
        }
    }
}
Пример ответа
{
    "took": 42,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 4,
            "relation": "eq"
        },
        "max_score": 0.5833334,
        "hits": [
            {
                "_index": "retrievers_example",
                "_id": "5",
                "_score": 0.5833334
            },
            {
                "_index": "retrievers_example",
                "_id": "1",
                "_score": 0.5
            },
            {
                "_index": "retrievers_example",
                "_id": "4",
                "_score": 0.5
            },
            {
                "_index": "retrievers_example",
                "_id": "3",
                "_score": 0.33333334
            }
        ]
    },
    "aggregations": {
        "topics": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
                {
                    "key": "ai",
                    "doc_count": 3
                },
                {
                    "key": "elastic",
                    "doc_count": 2
                },
                {
                    "key": "assistant",
                    "doc_count": 1
                },
                {
                    "key": "documentation",
                    "doc_count": 1
                },
                {
                    "key": "information_retrieval",
                    "doc_count": 1
                },
                {
                    "key": "llm",
                    "doc_count": 1
                },
                {
                    "key": "observability",
                    "doc_count": 1
                },
                {
                    "key": "security",
                    "doc_count": 1
                }
            ]
        }
    }
}

Пример: Объяснимость с несколькими извлекателями

Добавив explain: true в запрос, каждый извлекатель теперь предоставит подробное объяснение всех шагов и вычислений, необходимых для вычисления итогового результата. Композиция полностью поддерживается в контексте explain, и каждый извлекатель предоставит своё объяснение, как показано в примере ниже.

resp = client.search(
    index="retrievers_example",
    retriever={
        "rrf": {
            "retrievers": [
                {
                    "standard": {
                        "query": {
                            "term": {
                                "topic": "elastic"
                            }
                        }
                    }
                },
                {
                    "rrf": {
                        "retrievers": [
                            {
                                "standard": {
                                    "query": {
                                        "query_string": {
                                            "query": "(information retrieval) OR (artificial intelligence)",
                                            "default_field": "text"
                                        }
                                    }
                                }
                            },
                            {
                                "knn": {
                                    "field": "vector",
                                    "query_vector": [
                                        0.23,
                                        0.67,
                                        0.89
                                    ],
                                    "k": 3,
                                    "num_candidates": 5
                                }
                            }
                        ],
                        "rank_window_size": 10,
                        "rank_constant": 1
                    }
                }
            ],
            "rank_window_size": 10,
            "rank_constant": 1
        }
    },
    source=False,
    size=1,
    explain=True,
)
print(resp)
const response = await client.search({
  index: "retrievers_example",
  retriever: {
    rrf: {
      retrievers: [
        {
          standard: {
            query: {
              term: {
                topic: "elastic",
              },
            },
          },
        },
        {
          rrf: {
            retrievers: [
              {
                standard: {
                  query: {
                    query_string: {
                      query:
                        "(information retrieval) OR (artificial intelligence)",
                      default_field: "text",
                    },
                  },
                },
              },
              {
                knn: {
                  field: "vector",
                  query_vector: [0.23, 0.67, 0.89],
                  k: 3,
                  num_candidates: 5,
                },
              },
            ],
            rank_window_size: 10,
            rank_constant: 1,
          },
        },
      ],
      rank_window_size: 10,
      rank_constant: 1,
    },
  },
  _source: false,
  size: 1,
  explain: true,
});
console.log(response);
GET /retrievers_example/_search
{
    "retriever": {
        "rrf": {
            "retrievers": [
                {
                    "standard": {
                        "query": {
                            "term": {
                                "topic": "elastic"
                            }
                        }
                    }
                },
                {
                    "rrf": {
                        "retrievers": [
                            {
                                "standard": {
                                    "query": {
                                        "query_string": {
                                            "query": "(information retrieval) OR (artificial intelligence)",
                                            "default_field": "text"
                                        }
                                    }
                                }
                            },
                            {
                                "knn": {
                                    "field": "vector",
                                    "query_vector": [
                                        0.23,
                                        0.67,
                                        0.89
                                    ],
                                    "k": 3,
                                    "num_candidates": 5
                                }
                            }
                        ],
                        "rank_window_size": 10,
                        "rank_constant": 1
                    }
                }
            ],
            "rank_window_size": 10,
            "rank_constant": 1
        }
    },
    "_source": false,
    "size": 1,
    "explain": true
}

Выход, хотя и немного подробный, предоставит всю необходимую информацию для отладки и осмысления ранжирования.

Пример ответа
{
    "took": 42,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 5,
            "relation": "eq"
        },
        "max_score": 0.5,
        "hits": [
            {
                "_shard": "[retrievers_example][0]",
                "_node": "jnrdZFKS3abUgWVsVdj2Vg",
                "_index": "retrievers_example",
                "_id": "1",
                "_score": 0.5,
                "_explanation": {
                    "value": 0.5,
                    "description": "rrf score: [0.5] computed for initial ranks [0, 1] with rankConstant: [1] as sum of [1 / (rank + rankConstant)] for each query",
                    "details": [
                        {
                            "value": 0.0,
                            "description": "rrf score: [0], result not found in query at index [0]",
                            "details": []
                        },
                        {
                            "value": 1,
                            "description": "rrf score: [0.5], for rank [1] in query at index [1] computed as [1 / (1 + 1)], for matching query with score",
                            "details": [
                                {
                                    "value": 0.8333334,
                                    "description": "rrf score: [0.8333334] computed for initial ranks [2, 1] with rankConstant: [1] as sum of [1 / (rank + rankConstant)] for each query",
                                    "details": [
                                        {
                                            "value": 2,
                                            "description": "rrf score: [0.33333334], for rank [2] in query at index [0] computed as [1 / (2 + 1)], for matching query with score",
                                            "details": [
                                                {
                                                    "value": 2.8129659,
                                                    "description": "sum of:",
                                                    "details": [
                                                        {
                                                            "value": 1.4064829,
                                                            "description": "weight(text:information in 0) [PerFieldSimilarity], result of:",
                                                            "details": [
                                                                ***
                                                            ]
                                                        },
                                                        {
                                                            "value": 1.4064829,
                                                            "description": "weight(text:retrieval in 0) [PerFieldSimilarity], result of:",
                                                            "details": [
                                                                ***
                                                            ]
                                                        }
                                                    ]
                                                }
                                            ]
                                        },
                                        {
                                            "value": 1,
                                            "description": "rrf score: [0.5], for rank [1] in query at index [1] computed as [1 / (1 + 1)], for matching query with score",
                                            "details": [
                                                {
                                                    "value": 1,
                                                    "description": "doc [0] with an original score of [1.0] is at rank [1] from the following source queries.",
                                                    "details": [
                                                        {
                                                            "value": 1.0,
                                                            "description": "found vector with calculated similarity: 1.0",
                                                            "details": []
                                                        }
                                                    ]
                                                }
                                            ]
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            }
        ]
    }
}

Пример: Переранжирование результатов извлекателя RRF

Для демонстрации полной функциональности извлекателей следующие примеры также требуют доступа к модели семантического переранжирования, настроенной с использованием API вывода.

В этом примере мы настроим службу переранжирования и используем её с извлекателем text_similarity_reranker для переранжирования наших лучших результатов.

resp = client.inference.put(
    task_type="rerank",
    inference_id="my-rerank-model",
    inference_config={
        "service": "cohere",
        "service_settings": {
            "model_id": "rerank-english-v3.0",
            "api_key": "{{COHERE_API_KEY}}"
        }
    },
)
print(resp)
const response = await client.inference.put({
  task_type: "rerank",
  inference_id: "my-rerank-model",
  inference_config: {
    service: "cohere",
    service_settings: {
      model_id: "rerank-english-v3.0",
      api_key: "{{COHERE_API_KEY}}",
    },
  },
});
console.log(response);
PUT _inference/rerank/my-rerank-model
{
 "service": "cohere",
 "service_settings": {
   "model_id": "rerank-english-v3.0",
   "api_key": "{{COHERE_API_KEY}}"
 }
}

Начнём с переранжирования результатов извлекателя rrf в предыдущем примере.

resp = client.search(
    index="retrievers_example",
    retriever={
        "text_similarity_reranker": {
            "retriever": {
                "rrf": {
                    "retrievers": [
                        {
                            "standard": {
                                "query": {
                                    "query_string": {
                                        "query": "(information retrieval) OR (artificial intelligence)",
                                        "default_field": "text"
                                    }
                                }
                            }
                        },
                        {
                            "knn": {
                                "field": "vector",
                                "query_vector": [
                                    0.23,
                                    0.67,
                                    0.89
                                ],
                                "k": 3,
                                "num_candidates": 5
                            }
                        }
                    ],
                    "rank_window_size": 10,
                    "rank_constant": 1
                }
            },
            "field": "text",
            "inference_id": "my-rerank-model",
            "inference_text": "What are the state of the art applications of AI in information retrieval?"
        }
    },
    source=False,
)
print(resp)
const response = await client.search({
  index: "retrievers_example",
  retriever: {
    text_similarity_reranker: {
      retriever: {
        rrf: {
          retrievers: [
            {
              standard: {
                query: {
                  query_string: {
                    query:
                      "(information retrieval) OR (artificial intelligence)",
                    default_field: "text",
                  },
                },
              },
            },
            {
              knn: {
                field: "vector",
                query_vector: [0.23, 0.67, 0.89],
                k: 3,
                num_candidates: 5,
              },
            },
          ],
          rank_window_size: 10,
          rank_constant: 1,
        },
      },
      field: "text",
      inference_id: "my-rerank-model",
      inference_text:
        "What are the state of the art applications of AI in information retrieval?",
    },
  },
  _source: false,
});
console.log(response);
GET retrievers_example/_search
{
    "retriever": {
        "text_similarity_reranker": {
            "retriever": {
                "rrf": {
                    "retrievers": [
                        {
                            "standard": {
                                "query": {
                                    "query_string": {
                                        "query": "(information retrieval) OR (artificial intelligence)",
                                        "default_field": "text"
                                    }
                                }
                            }
                        },
                        {
                            "knn": {
                                "field": "vector",
                                "query_vector": [
                                    0.23,
                                    0.67,
                                    0.89
                                ],
                                "k": 3,
                                "num_candidates": 5
                            }
                        }
                    ],
                    "rank_window_size": 10,
                    "rank_constant": 1
                }
            },
            "field": "text",
            "inference_id": "my-rerank-model",
            "inference_text": "What are the state of the art applications of AI in information retrieval?"
        }
    },
    "_source": false
}

Пример: RRF с семантическим переранжирователем

В этом примере мы заменим извлекатель standard rrf на извлекатель text_similarity_reranker, используя ранее настроенный переранжирователь my-rerank-model. Поскольку это переранжирователь, ему требуется начальный пул документов для работы. В данном случае мы переранжируем первые rank_window_size документов, соответствующих теме ai.

resp = client.search(
    index="retrievers_example",
    retriever={
        "rrf": {
            "retrievers": [
                {
                    "knn": {
                        "field": "vector",
                        "query_vector": [
                            0.23,
                            0.67,
                            0.89
                        ],
                        "k": 3,
                        "num_candidates": 5
                    }
                },
                {
                    "text_similarity_reranker": {
                        "retriever": {
                            "standard": {
                                "query": {
                                    "term": {
                                        "topic": "ai"
                                    }
                                }
                            }
                        },
                        "field": "text",
                        "inference_id": "my-rerank-model",
                        "inference_text": "Can I use generative AI to identify user intent and improve search relevance?"
                    }
                }
            ],
            "rank_window_size": 10,
            "rank_constant": 1
        }
    },
    source=False,
)
print(resp)
const response = await client.search({
  index: "retrievers_example",
  retriever: {
    rrf: {
      retrievers: [
        {
          knn: {
            field: "vector",
            query_vector: [0.23, 0.67, 0.89],
            k: 3,
            num_candidates: 5,
          },
        },
        {
          text_similarity_reranker: {
            retriever: {
              standard: {
                query: {
                  term: {
                    topic: "ai",
                  },
                },
              },
            },
            field: "text",
            inference_id: "my-rerank-model",
            inference_text:
              "Can I use generative AI to identify user intent and improve search relevance?",
          },
        },
      ],
      rank_window_size: 10,
      rank_constant: 1,
    },
  },
  _source: false,
});
console.log(response);
GET /retrievers_example/_search
{
    "retriever": {
        "rrf": {
            "retrievers": [
                {
                    "knn": {
                        "field": "vector",
                        "query_vector": [
                            0.23,
                            0.67,
                            0.89
                        ],
                        "k": 3,
                        "num_candidates": 5
                    }
                },
                {
                    "text_similarity_reranker": {
                        "retriever": {
                            "standard": {
                                "query": {
                                    "term": {
                                        "topic": "ai"
                                    }
                                }
                            }
                        },
                        "field": "text",
                        "inference_id": "my-rerank-model",
                        "inference_text": "Can I use generative AI to identify user intent and improve search relevance?"
                    }
                }
            ],
            "rank_window_size": 10,
            "rank_constant": 1
        }
    },
    "_source": false
}

Пример: Цепочечное подключение нескольких семантических переранжирователей

Полная композиция означает, что мы можем связать несколько извлекателей одного типа. Например, представьте, что у нас есть вычислительно сложный переранжирователь, специализирующийся на контенте искусственного интеллекта. Мы можем переранжировать результаты поиска text_similarity_reranker с помощью другого извлекателя text_similarity_reranker переранжирования. Каждый переранжирователь может работать с разными полями и/или использовать разные сервисы вывода.

resp = client.search(
    index="retrievers_example",
    retriever={
        "text_similarity_reranker": {
            "retriever": {
                "text_similarity_reranker": {
                    "retriever": {
                        "knn": {
                            "field": "vector",
                            "query_vector": [
                                0.23,
                                0.67,
                                0.89
                            ],
                            "k": 3,
                            "num_candidates": 5
                        }
                    },
                    "rank_window_size": 100,
                    "field": "text",
                    "inference_id": "my-rerank-model",
                    "inference_text": "What are the state of the art applications of AI in information retrieval?"
                }
            },
            "rank_window_size": 10,
            "field": "text",
            "inference_id": "my-other-more-expensive-rerank-model",
            "inference_text": "Applications of Large Language Models in technology and their impact on user satisfaction"
        }
    },
    source=False,
)
print(resp)
const response = await client.search({
  index: "retrievers_example",
  retriever: {
    text_similarity_reranker: {
      retriever: {
        text_similarity_reranker: {
          retriever: {
            knn: {
              field: "vector",
              query_vector: [0.23, 0.67, 0.89],
              k: 3,
              num_candidates: 5,
            },
          },
          rank_window_size: 100,
          field: "text",
          inference_id: "my-rerank-model",
          inference_text:
            "What are the state of the art applications of AI in information retrieval?",
        },
      },
      rank_window_size: 10,
      field: "text",
      inference_id: "my-other-more-expensive-rerank-model",
      inference_text:
        "Applications of Large Language Models in technology and their impact on user satisfaction",
    },
  },
  _source: false,
});
console.log(response);
GET retrievers_example/_search
{
    "retriever": {
        "text_similarity_reranker": {
            "retriever": {
                "text_similarity_reranker": {
                    "retriever": {
                        "knn": {
                            "field": "vector",
                            "query_vector": [
                                0.23,
                                0.67,
                                0.89
                            ],
                            "k": 3,
                            "num_candidates": 5
                        }
                    },
                    "rank_window_size": 100,
                    "field": "text",
                    "inference_id": "my-rerank-model",
                    "inference_text": "What are the state of the art applications of AI in information retrieval?"
                }
            },
            "rank_window_size": 10,
            "field": "text",
            "inference_id": "my-other-more-expensive-rerank-model",
            "inference_text": "Applications of Large Language Models in technology and their impact on user satisfaction"
        }
    },
    "_source": false
}

Обратите внимание, что наш пример выполняет два шага переранжирования. Сначала мы переранжируем первые 100 документов из поиска knn с помощью переранжирователя my-rerank-model. Затем мы выбираем лучшие 10 результатов и переранжируем их с помощью более точного переранжирователя my-other-more-expensive-rerank-model.

© 2023-2025 Elasticsearch
As of September 2024, Elasticsearch is available under a choice of three licenses: the Server Side Public License (SSPL), the Elastic License, or the AGPLv3 (OSI approved).
Elasticsearch and the Elasticsearch logo are trademarks of Elasticsearch B.V., registered in the U.S. and in other countries.
https://www.elastic.co/guide/en/elasticsearch/reference/8.17/_retrievers_examples.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API