Elasticsearch BM25 检索器连接问题解决方案
1 问题分析
在 SafeRAG 项目中使用 BM25 检索器时遇到 Elasticsearch 连接问题。根本原因包括:
- 协议不匹配: 原代码使用 HTTP 连接,但 Elasticsearch 9.2.0 默认启用了 HTTPS
- 缺少身份验证: Elasticsearch 启用了安全特性,需要用户名和密码认证
- 客户端类型错误 :
llama_index的ElasticsearchStore需要异步客户端,但原代码使用同步客户端
2 问题排查步骤
1. 检查 Elasticsearch 服务状态
sudo systemctl status elasticsearch
确认服务正在运行
2. 检查端口监听
sudo lsof -i :9200
确认 Elasticsearch 在 9200 端口监听
3. 测试连接
# 测试 HTTP 连接(会失败)
curl http://localhost:9200
# 测试 HTTPS 连接(需要认证)
curl -k https://localhost:9200
# 使用认证测试
curl -k -u elastic:PASSWORD https://localhost:9200
4. 重置 Elasticsearch 密码
sudo /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic
记录生成的新密码
5. 查看错误日志
sudo tail -n 100 /var/log/elasticsearch/elasticsearch.log
关键错误信息:
received plaintext http traffic on an https channel- 协议不匹配TypeError: object HeadApiResponse can't be used in 'await' expression- 客户端类型错误
3 解决方案1 (最简单)
完全禁用 Elasticsearch 安全功能
编辑 elasticsearch.yml 配置文件:
bash
sudo vim /etc/elasticsearch/elasticsearch.yml
完全禁用安全功能 ,将3个地方设置为false
txt
xpack.security.enabled: false
xpack.security.http.ssl.enabled: false
xpack.security.transport.ssl.enabled: false
重启服务
bash
sudo systemctl restart elasticsearch
4 解决方案2
(1)修改 retrievers/bm25.py 文件
修改客户端初始化 (第50行)
修改前:
self.es_client = Elasticsearch([{'host': 'localhost', 'port': 9200, "scheme": "http"}])
修改后:
from elasticsearch import AsyncElasticsearch
self.es_client = AsyncElasticsearch(
["https://localhost:9200"],
basic_auth=("elastic", "YOUR_PASSWORD"), # 使用重置后的密码
verify_certs=False,
ssl_show_warn=False
)
修改 construct_index 方法 (约第79行)
修改前:
vector_store = ElasticsearchStore(
index_name=self.collection_name,
es_url="http://localhost:9200"
)
修改后:
vector_store = ElasticsearchStore(
index_name=self.collection_name,
es_client=self.es_client # 传入配置好的客户端
)
- 修改
construct_attack_index方法 (约第118行)
同样将 es_url 参数改为 es_client 参数
总结:
- 使用
AsyncElasticsearch:llama_index的ElasticsearchStore内部使用异步操作,必须传入异步客户端 - HTTPS 协议 : Elasticsearch 9.2.0 默认启用 SSL/TLS,需使用
https://协议 - 禁用证书验证 : 开发环境中使用
verify_certs=False跳过自签名证书验证 - 传入客户端对象 : 使用
es_client参数而非es_url,以完全控制客户端配置