检索器示例

编辑

添加示例数据

编辑

首先,让我们创建 retrievers_example 索引,并向其中添加一些文档。

const response = await client.indices.create({
  index: "retrievers_example",
  mappings: {
    properties: {
      vector: {
        type: "dense_vector",
        dims: 3,
        similarity: "l2_norm",
        index: true,
      },
      text: {
        type: "text",
      },
      year: {
        type: "integer",
      },
      topic: {
        type: "keyword",
      },
    },
  },
});
console.log(response);

const response1 = await client.index({
  index: "retrievers_example",
  id: 1,
  document: {
    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"],
  },
});
console.log(response1);

const response2 = await client.index({
  index: "retrievers_example",
  id: 2,
  document: {
    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"],
  },
});
console.log(response2);

const response3 = await client.index({
  index: "retrievers_example",
  id: 3,
  document: {
    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"],
  },
});
console.log(response3);

const response4 = await client.index({
  index: "retrievers_example",
  id: 4,
  document: {
    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"],
  },
});
console.log(response4);

const response5 = await client.index({
  index: "retrievers_example",
  id: 5,
  document: {
    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"],
  },
});
console.log(response5);

const response6 = await client.indices.refresh({
  index: "retrievers_example",
});
console.log(response6);
PUT retrievers_example
{
   "mappings": {
       "properties": {
           "vector": {
               "type": "dense_vector",
               "dims": 3,
               "similarity": "l2_norm",
               "index": true
           },
           "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 查询。 虽然这些查询可能会产生不同范围内的分数,但我们可以使用倒数排名融合 (rrf) 来合并结果并生成合并的最终结果列表。

为了在检索器框架中实现这一点,我们从顶级元素开始:我们的 rrf 检索器。 此检索器在另外两个检索器之上运行:一个 knn 检索器和一个 standard 检索器。 我们的查询结构如下所示

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 参数来清理此问题。 与标准的 collapse 功能一样,这允许按任何字段对结果进行分组,并且仅返回每个组中得分最高的文档。 在此示例中,我们将基于 year 字段折叠我们的结果。

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 检索器,其中 knnstandard 检索器作为其子检索器。 我们可以指定一个 highlight 部分,如 突出显示 文档中所定义的那样,并计算顶部结果的突出显示。

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
}

这将基于 standard 检索器产生的匹配项突出显示 text 字段。 然后,突出显示的代码段将像往常一样包含在响应中,即在每个搜索命中之下。

示例响应
{
    "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 字段下,并索引一些文档。

const response = await client.indices.create({
  index: "retrievers_example_nested",
  mappings: {
    properties: {
      nested_field: {
        type: "nested",
        properties: {
          paragraph_id: {
            type: "keyword",
          },
          nested_vector: {
            type: "dense_vector",
            dims: 3,
            similarity: "l2_norm",
            index: true,
          },
        },
      },
      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
{
    "mappings": {
        "properties": {
            "nested_field": {
                "type": "nested",
                "properties": {
                    "paragraph_id": {
                        "type": "keyword"
                    },
                    "nested_vector": {
                        "type": "dense_vector",
                        "dims": 3,
                        "similarity": "l2_norm",
                        "index": true
                    }
                }
            },
            "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 检索器查询,并基于指定的 knn 查询,计算 nested_field.nested_vector 字段的 内部命中

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"
    ]
}

这会将为 knn 查询定义的 inner_hits 传播到 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.44353113,
                            "hits": [
                                {
                                    "_index": "retrievers_example_nested",
                                    "_id": "1",
                                    "_nested": {
                                        "field": "nested_field",
                                        "offset": 2
                                    },
                                    "_score": 0.44353113,
                                    "fields": {
                                        "nested_field": [
                                            {
                                                "paragraph_id": [
                                                    "1c"
                                                ]
                                            }
                                        ]
                                    }
                                },
                                {
                                    "_index": "retrievers_example_nested",
                                    "_id": "1",
                                    "_nested": {
                                        "field": "nested_field",
                                        "offset": 1
                                    },
                                    "_score": 0.26567122,
                                    "fields": {
                                        "nested_field": [
                                            {
                                                "paragraph_id": [
                                                    "1b"
                                                ]
                                            }
                                        ]
                                    }
                                },
                                {
                                    "_index": "retrievers_example_nested",
                                    "_id": "1",
                                    "_nested": {
                                        "field": "nested_field",
                                        "offset": 0
                                    },
                                    "_score": 0.18478848,
                                    "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.32002488,
                            "hits": [
                                {
                                    "_index": "retrievers_example_nested",
                                    "_id": "2",
                                    "_nested": {
                                        "field": "nested_field",
                                        "offset": 0
                                    },
                                    "_score": 0.32002488,
                                    "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 检索器计算聚合。 使用复合检索器时,聚合是基于其嵌套的检索器计算的。 在以下示例中,topic 字段的 terms 聚合将包括所有结果,而不仅仅是来自 2 个嵌套检索器的前 rank_window_size,即其 year 字段大于 2023 且其 topic 字段与术语 elastic 匹配的所有文档。

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 的上下文中完全支持可组合性,每个检索器都将提供自己的解释,如下例所示。

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 检索器的结果

编辑

为了演示检索器的全部功能,以下示例还需要访问使用 Elastic 推理 API 设置的语义重新排列模型

在此示例中,我们将设置一个重新排列服务,并将其与 text_similarity_reranker 检索器一起使用以重新排列我们的顶部结果。

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 检索器的结果。

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

编辑

在此示例中,我们将使用 text_similarity_reranker 检索器替换 rrf 的 standard 检索器,使用我们先前配置的 my-rerank-model 重新排列器。 由于这是一个重新排列器,因此它需要一个初始文档池才能使用。 在这种情况下,我们将重新排列与 ai 主题匹配的前 rank_window_size 文档。

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
}

示例:链接多个语义重新排列器

编辑

完全的可组合性意味着我们可以将多个相同类型的检索器链接在一起。 例如,假设我们有一个计算成本高昂的重新排列器,专门用于 AI 内容。 我们可以使用另一个 text_similarity_reranker 检索器来重新排列 text_similarity_reranker 的结果。 每个重新排列器都可以对不同的字段进行操作和/或使用不同的推理服务。

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
}

请注意,我们的示例应用了两个重新排列步骤。 首先,我们使用 my-rerank-model 重新排列器重新排列来自 knn 搜索的前 100 个文档。 然后,我们选择前 10 个结果,并使用更精细的 my-other-more-expensive-rerank-model 重新排列它们。