Elasticsearch:BM25 及 使用 Elasticsearch 和 LangChain 的自查询检索器

2024-02-07 04:04

本文主要是介绍Elasticsearch:BM25 及 使用 Elasticsearch 和 LangChain 的自查询检索器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本工作簿演示了 Elasticsearch 的自查询检索器将非结构化查询转换为结构化查询的示例,我们将其用于 BM25 示例。

在这个例子中:

  • 我们将摄取 LangChain 之外的电影样本数据集
  • 自定义 ElasticsearchStore 中的检索策略以仅使用 BM25
  • 使用自查询检索将问题转换为结构化查询
  • 使用文档和 RAG 策略来回答问题

安装

如果你还没有安装好自己的 Elasticsearch 及 Kibana,请参考文章:

安装 Elasticsearch 及 Kibana

如果你还没有安装好自己的 Elasticsearch 及 Kibana,那么请参考一下的文章来进行安装:

  • 如何在 Linux,MacOS 及 Windows 上进行安装 Elasticsearch

  • Kibana:如何在 Linux,MacOS 及 Windows 上安装 Elastic 栈中的 Kibana

在安装的时候,请选择 Elastic Stack 8.x 进行安装。在安装的时候,我们可以看到如下的安装信息:

Python 安装包

我们需要安装 Python 版本 3.6 及以上版本。我们还需要安装如下的 Python 安装包:

pip3 install lark elasticsearch langchain openai load_dotenv
$ pip3 list | grep elasticsearch
elasticsearch                            8.12.0
rag-elasticsearch                        0.0.1        /Users/liuxg/python/rag-elasticsearch/my-app/packages/rag-elasticsearch

环境变量

在启动 Jupyter 之前,我们设置如下的环境变量:

export ES_USER="elastic"
export ES_PASSWORD="xnLj56lTrH98Lf_6n76y"
export ES_ENDPOINT="localhost"
export OPENAI_API_KEY="YOUR_OPEN_AI_KEY"

请在上面修改相应的变量的值。特别是你需要输入自己的 OPENAI_API_KEY。

拷贝 Elasticsearch 证书

我们把 Elasticsearch 的证书拷贝到当前的目录下:

$ pwd
/Users/liuxg/python/elser
$ cp ~/elastic/elasticsearch-8.12.0/config/certs/http_ca.crt .
$ ls http_ca.crt 
http_ca.crt

创建应用

我们在当前的目录下运行 jupyter notebook:

jupyter notebook

连接到 Elasticsearch

from elasticsearch import Elasticsearch
from dotenv import load_dotenv
import os
from elasticsearch import Elasticsearchload_dotenv()openai_api_key=os.getenv('OPENAI_API_KEY')
elastic_user=os.getenv('ES_USER')
elastic_password=os.getenv('ES_PASSWORD')
elastic_endpoint=os.getenv("ES_ENDPOINT")url = f"https://{elastic_user}:{elastic_password}@{elastic_endpoint}:9200"
client = Elasticsearch(url, ca_certs = "./http_ca.crt", verify_certs = True)print(client.info())

准备示例数据集

docs = [{"text": "A bunch of scientists bring back dinosaurs and mayhem breaks loose","metadata": {"year": 1993, "rating": 7.7, "genre": "science fiction", "director": "Steven Spielberg", "title": "Jurassic Park"},},{"text": "Leo DiCaprio gets lost in a dream within a dream within a dream within a ...","metadata": {"year": 2010, "director": "Christopher Nolan", "rating": 8.2, "title": "Inception"},},{"text": "A psychologist / detective gets lost in a series of dreams within dreams within dreams and Inception reused the idea","metadata": {"year": 2006, "director": "Satoshi Kon", "rating": 8.6, "title": "Paprika"},},{"text":"A bunch of normal-sized women are supremely wholesome and some men pine after them","metadata":{"year": 2019, "director": "Greta Gerwig", "rating": 8.3, "title": "Little Women"},},{"text":"Toys come alive and have a blast doing so","metadata":{"year": 1995, "genre": "animated", "director": "John Lasseter", "rating": 8.3, "title": "Toy Story"},},{"text":"Three men walk into the Zone, three men walk out of the Zone","metadata":{"year": 1979,"rating": 9.9,"director": "Andrei Tarkovsky","genre": "science fiction","rating": 9.9,"title": "Stalker",}}
]

索引数据到 Elasticsearch

我们选择对 Langchain 外部的数据进行索引,以演示如何将 Langchain 用于 RAG 并在任何 Elasticsearch 索引上使用自查询检索。

from elasticsearch import helpers# create the index
client.indices.create(index="movies_self_query")operations = [{"_index": "movies_self_query","_id": i,"text": doc["text"],"metadata": doc["metadata"]} for i, doc in enumerate(docs)
]# Add the documents to the index directly
response = helpers.bulk(client,operations,
)

经过上面的操作后,我们可以在 Kibana 中进行查看:

设置查询检索器

接下来,我们将通过提供有关文档属性的一些信息和有关文档的简短描述来实例化自查询检索器。

然后我们将使用 SelfQueryRetriever.from_llm 实例化检索器

from langchain.vectorstores.elasticsearch import ApproxRetrievalStrategy
from typing import List, Union
from langchain.retrievers.self_query.base import SelfQueryRetriever
from langchain.chains.query_constructor.base import AttributeInfo
from langchain.llms import OpenAI
from langchain.vectorstores.elasticsearch import ElasticsearchStore# Add details about metadata fields
metadata_field_info = [AttributeInfo(name="genre",description="The genre of the movie. Can be either 'science fiction' or 'animated'.",type="string or list[string]",),AttributeInfo(name="year",description="The year the movie was released",type="integer",),AttributeInfo(name="director",description="The name of the movie director",type="string",),AttributeInfo(name="rating", description="A 1-10 rating for the movie", type="float"),
]document_content_description = "Brief summary of a movie"# Set up openAI llm with sampling temperature 0
llm = OpenAI(temperature=0, openai_api_key=openai_api_key)class BM25RetrievalStrategy(ApproxRetrievalStrategy):def __init__(self):passdef query(self,query: Union[str, None],filter: List[dict],**kwargs,):if query:query_clause = [{"multi_match": {"query": query,"fields": ["text"],"fuzziness": "AUTO",}}]else:query_clause = []bm25_query = {"query": {"bool": {"filter": filter,"must": query_clause}},}print("query", bm25_query)return bm25_queryvectorstore = ElasticsearchStore(index_name="movies_self_query",es_connection=client,strategy=BM25RetrievalStrategy()
)

仅使用 BM25 的检索器 

一种选择是自定义查询以仅使用 BM25 检索方法。 我们可以通过重写 custom_query 函数,指定查询仅使用 multi_match 来做到这一点。

在下面的示例中,自查询检索器使用 LLM 将问题转换为关键字和过滤器查询(query: dreams, filter: year range)。 然后使用自定义查询对关键字查询和过滤器查询执行基于 BM25 的查询。

这意味着如果你想在现有 Elasticsearch 索引上执行问题/答案用例,则不必对所有文档进行向量化。

from langchain.schema.runnable import RunnableParallel, RunnablePassthrough
from langchain.prompts import ChatPromptTemplate, PromptTemplate
from langchain.schema import format_documentretriever = SelfQueryRetriever.from_llm(llm, vectorstore, document_content_description, metadata_field_info, verbose=True
)LLM_CONTEXT_PROMPT = ChatPromptTemplate.from_template("""
Use the following context movies that matched the user question. Use the movies below only to answer the user's question.If you don't know the answer, just say that you don't know, don't try to make up an answer.----
{context}
----
Question: {question}
Answer:
""")DOCUMENT_PROMPT = PromptTemplate.from_template("""
---
title: {title}                                                                                   
year: {year}  
director: {director}     
---
""")def _combine_documents(docs, document_prompt=DOCUMENT_PROMPT, document_separator="\n\n"
):print("docs:", docs)doc_strings = [format_document(doc, document_prompt) for doc in docs]return document_separator.join(doc_strings)_context = RunnableParallel(context=retriever | _combine_documents,question=RunnablePassthrough(),
)chain = (_context | LLM_CONTEXT_PROMPT | llm)chain.invoke("Which director directed movies about dinosaurs that was released after the year 1992 but before 2007?")

整个 notebook 的源码可以在地址下载:https://github.com/liu-xiao-guo/semantic_search_es/blob/main/chatbot-with-bm25-only-example.ipynb

这篇关于Elasticsearch:BM25 及 使用 Elasticsearch 和 LangChain 的自查询检索器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/686465

相关文章

setsid 命令工作原理和使用案例介绍

《setsid命令工作原理和使用案例介绍》setsid命令在Linux中创建独立会话,使进程脱离终端运行,适用于守护进程和后台任务,通过重定向输出和确保权限,可有效管理长时间运行的进程,本文给大家介... 目录setsid 命令介绍和使用案例基本介绍基本语法主要特点命令参数使用案例1. 在后台运行命令2.

使用Redis快速实现共享Session登录的详细步骤

《使用Redis快速实现共享Session登录的详细步骤》在Web开发中,Session通常用于存储用户的会话信息,允许用户在多个页面之间保持登录状态,Redis是一个开源的高性能键值数据库,广泛用于... 目录前言实现原理:步骤:使用Redis实现共享Session登录1. 引入Redis依赖2. 配置R

使用Python的requests库调用API接口的详细步骤

《使用Python的requests库调用API接口的详细步骤》使用Python的requests库调用API接口是开发中最常用的方式之一,它简化了HTTP请求的处理流程,以下是详细步骤和实战示例,涵... 目录一、准备工作:安装 requests 库二、基本调用流程(以 RESTful API 为例)1.

使用Python开发一个Ditto剪贴板数据导出工具

《使用Python开发一个Ditto剪贴板数据导出工具》在日常工作中,我们经常需要处理大量的剪贴板数据,下面将介绍如何使用Python的wxPython库开发一个图形化工具,实现从Ditto数据库中读... 目录前言运行结果项目需求分析技术选型核心功能实现1. Ditto数据库结构分析2. 数据库自动定位3

Python yield与yield from的简单使用方式

《Pythonyield与yieldfrom的简单使用方式》生成器通过yield定义,可在处理I/O时暂停执行并返回部分结果,待其他任务完成后继续,yieldfrom用于将一个生成器的值传递给另一... 目录python yield与yield from的使用代码结构总结Python yield与yield

Go语言使用select监听多个channel的示例详解

《Go语言使用select监听多个channel的示例详解》本文将聚焦Go并发中的一个强力工具,select,这篇文章将通过实际案例学习如何优雅地监听多个Channel,实现多任务处理、超时控制和非阻... 目录一、前言:为什么要使用select二、实战目标三、案例代码:监听两个任务结果和超时四、运行示例五

python使用Akshare与Streamlit实现股票估值分析教程(图文代码)

《python使用Akshare与Streamlit实现股票估值分析教程(图文代码)》入职测试中的一道题,要求:从Akshare下载某一个股票近十年的财务报表包括,资产负债表,利润表,现金流量表,保存... 目录一、前言二、核心知识点梳理1、Akshare数据获取2、Pandas数据处理3、Matplotl

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Oracle查询表结构建表语句索引等方式

《Oracle查询表结构建表语句索引等方式》使用USER_TAB_COLUMNS查询表结构可避免系统隐藏字段(如LISTUSER的CLOB与VARCHAR2同名字段),这些字段可能为dbms_lob.... 目录oracle查询表结构建表语句索引1.用“USER_TAB_COLUMNS”查询表结构2.用“a

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我