[深入浅出ElasticsearchRetriever——全面掌握Elasticsearch的搜索引擎潜力]

104 阅读3分钟
# 引言

Elasticsearch 是一个分布式的RESTful搜索和分析引擎,提供多租户的全文搜索引擎功能,同时支持HTTP接口和无模式的JSON文档。它不仅能够进行关键词搜索,还支持向量搜索、混合搜索和复杂过滤等功能。而 `ElasticsearchRetriever` 是一个通用的包装类,通过Query DSL提供对所有Elasticsearch功能的灵活访问。本文旨在帮助您起步使用ElasticsearchRetriever,并提供详细的代码示例和常见问题的解决方案。

# 主要内容

## 集成详情

`ElasticsearchRetriever` 支持自托管和云服务两种方式进行部署,相关包名为 `langchain_elasticsearch`## 安装与设置

您可以通过以下命令安装必须的库:

```bash
%pip install -qU langchain-community langchain-elasticsearch

接下来设置您的Elasticsearch实例,可以选择本地安装或使用Elastic Cloud。

本地安装

使用官方的Elasticsearch Docker镜像进行本地安装,详情请参考 Elasticsearch Docker documentation

Elastic Cloud

注册Elastic Cloud并开启免费试用,可以获得一个无需登录就能访问的Elasticsearch实例。

from elasticsearch import Elasticsearch

es_url = "http://localhost:9200"  # 使用API代理服务提高访问稳定性
es_client = Elasticsearch(hosts=[es_url])
es_client.info()

配置示例数据

设置向量搜索所需的嵌入:

from langchain_community.embeddings import DeterministicFakeEmbedding

embeddings = DeterministicFakeEmbedding(size=3)

定义测试数据:

texts = ["foo", "bar", "world", "hello world", "hello", "foo bar", "bla bla foo"]
index_name = "test-langchain-retriever"

数据索引

创建一个索引并插入数据:

from elasticsearch.helpers import bulk
from typing import Iterable, Dict

def create_index(es_client: Elasticsearch, index_name: str, text_field: str, dense_vector_field: str, num_characters_field: str):
    es_client.indices.create(
        index=index_name,
        mappings={
            "properties": {
                text_field: {"type": "text"},
                dense_vector_field: {"type": "dense_vector"},
                num_characters_field: {"type": "integer"},
            }
        },
    )

def index_data(es_client: Elasticsearch, index_name: str, text_field: str, dense_vector_field: str, embeddings: Embeddings, texts: Iterable[str], refresh: bool = True) -> None:
    create_index(es_client, index_name, text_field, dense_vector_field, num_characters_field)

    vectors = embeddings.embed_documents(list(texts))
    requests = [
        {
            "_op_type": "index",
            "_index": index_name,
            "_id": i,
            text_field: text,
            dense_vector_field: vector,
            num_characters_field: len(text),
        }
        for i, (text, vector) in enumerate(zip(texts, vectors))
    ]

    bulk(es_client, requests)

    if refresh:
        es_client.indices.refresh(index=index_name)

查询示例

向量搜索

使用伪嵌入进行向量搜索:

def vector_query(search_query: str) -> Dict:
    vector = embeddings.embed_query(search_query)
    return {
        "knn": {
            "field": dense_vector_field,
            "query_vector": vector,
            "k": 5,
            "num_candidates": 10,
        }
    }

实例化向量检索器并查询:

from langchain_elasticsearch import ElasticsearchRetriever

vector_retriever = ElasticsearchRetriever.from_es_params(
    index_name=index_name,
    body_func=vector_query,
    content_field=text_field,
    url=es_url,
)

vector_retriever.invoke("foo")

混合搜索

结合向量搜索和BM25搜索:

def hybrid_query(search_query: str) -> Dict:
    vector = embeddings.embed_query(search_query)
    return {
        "query": {
            "match": {
                text_field: search_query,
            },
        },
        "knn": {
            "field": dense_vector_field,
            "query_vector": vector,
            "k": 5,
            "num_candidates": 10,
        },
        "rank": {"rrf": {}},
    }

hybrid_retriever = ElasticsearchRetriever.from_es_params(
    index_name=index_name,
    body_func=hybrid_query,
    content_field=text_field,
    url=es_url,
)

hybrid_retriever.invoke("foo")

常见问题和解决方案

  1. 连接错误:确保Elasticsearch实例正在运行并且端点正确配置。如果您在某些地区遇到访问问题,考虑使用API代理服务。
  2. 搜索结果不准确:检查您的查询DSL是否正确配置,尤其是在复杂查询中。

总结和进一步学习资源

ElasticsearchRetriever 提供了一种灵活而强大的方式来利用Elasticsearch的高级搜索功能。通过本文,您学习到了如何进行向量搜索、BM25搜索、混合搜索和复杂过滤。如果您想更深入地了解,还可以参考以下资源:

参考资料

如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!

---END---