橘智橘智
FakeOrange
预计阅读时间:6分钟33秒

Elasticsearch使用指南(Python)

Elasticsearch搜索引擎使用python sdk的指南!

0
0


前置准备


确保已安装 Elasticsearch 服务器并运行,Python 环境中安装了 elasticsearch 库。

pip install elasticsearch

1. 连接 Elasticsearch


首先,导入 elasticsearch 库并连接到运行的 Elasticsearch 实例。

#如果需要使用异步 async,需要使用AsyncElasticsearch, 在使用的时候 await es.xxx
from elasticsearch import Elasticsearch 
# 创建连接对象
es = Elasticsearch(hosts=["http://localhost:9200"])

2. 设置映射(Mapping)

映射是指为 Elasticsearch 索引中的文档字段定义数据类型。映射设置得当,可以提高索引和搜索的性能。例如,以下代码创建一个名为 my_index 的索引,并为其字段定义了数据类型。

# 定义映射
mapping = {
    "mappings": {
        "properties": {
            "title": {
                "type": "text"
            },
            "description": {
                "type": "text"
            },
            "publish_date": {
                "type": "date"
            },
            "author": {
                "type": "keyword"
            },
            "vector_field": {
                "type": "dense_vector",
                "dims": 128  # 假设向量维度是128
            }
        }
    }
}

# 创建索引
if not es.indices.exists(index="my_index"):
    es.indices.create(index="my_index", body=mapping)

注意事项


  • text 类型用于全文搜索;
  • keyword 类型适合短文本且不需要分词;
  • dense_vector 是向量类型,适用于基于向量的相似度计算。


3. 重置映射


若需重置索引的映射(Mapping),通常需要删除并重新创建索引。Elasticsearch 不支持在已有索引上直接更改映射,因此我们可以按以下步骤重置:

# 删除索引
es.indices.delete(index="my_index", ignore=[400, 404])

# 重新创建索引
es.indices.create(index="my_index", body=mappi


但是可以添加新的


4. 插入文档


接下来,我们在 my_index 索引中添加一些示例文档。

# 插入单个文档
doc1 = {
    "title": "Python教程",
    "description": "详细介绍Python编程语言的教程",
    "publish_date": "2023-11-01",
    "author": "张三",
    "vector_field": [0.1] * 128  # 示例向量
}

# 使用文档ID插入文档
es.index(index="my_index", id=1, document=doc1)

批量插入

可以使用 bulk API 一次插入多条记录,提高插入效率。

from elasticsearch.helpers import bulk

# 批量插入文档
actions = [
    {
        "_index": "my_index",
        "_id": 2,
        "_source": {
            "title": "机器学习基础",
            "description": "适合初学者的机器学习教程",
            "publish_date": "2024-01-10",
            "author": "李四",
            "vector_field": [0.2] * 128
        }
    },
    # 可以添加更多文档
]

bulk(es, actions)


此处添加的向量可以使用huggingface的sentence_transformer,后面会写更详细的教程。


5. 更新已有文档


Elasticsearch 提供了 update 方法来部分更新文档内容。以下是更新文档ID为 1 的示例。

# 部分更新文档
update_doc = {
    "doc": {
        "description": "更新后的Python教程描述"
    }
}

es.update(index="my_index", id=1, body=update_doc)

6. 基于向量和文本匹配的搜索


基本文本搜索

首先,我们可以使用 match 查询文本字段的全文搜索。例如,搜索包含“教程”的 title 文档。

# 简单文本搜索
query = {
    "query": {
        "match": {
            "title": "教程"
        }
    }
}

result = es.search(index="my_index", body=query)
for hit in result["hits"]["hits"]:
    print(hit["_source"])

基于向量的搜索

若需进行向量相似度搜索,Elasticsearch 支持 dense_vectorcosineSimilarity。以下示例展示如何基于向量字段 vector_field 进行相似度搜索:

# 示例向量查询
query_vector = [0.1] * 128  # 这是要匹配的查询向量

query = {
    "query": {
        "script_score": {
            "query": {"match_all": {}},
            "script": {
                "source": "cosineSimilarity(params.query_vector, 'vector_field') + 1.0",
                "params": {"query_vector": query_vector}
            }
        }
    }
}

result = es.search(index="my_index", body=query)
for hit in result["hits"]["hits"]:
    print(hit["_source"], "Score:", hit["_score"])


这里的 script_score 使用了 cosineSimilarity 函数计算向量相似度,通过 +1.0 避免相似度为负值。

基于向量和文本的复合搜索

可以结合 mustshould 条件,将文本匹配和向量相似度结合:

# 复合查询
query = {
    "query": {
        "bool": {
            "must": [
                {"match": {"title": "教程"}}
            ],
            "should": [
                {
                    "script_score": {
                        "query": {"match_all": {}},
                        "script": {
                            "source": "cosineSimilarity(params.query_vector, 'vector_field') + 1.0",
                            "params": {"query_vector": query_vector}
                        }
                    }
                }
            ]
        }
    }
}

result = es.search(index="my_index", body=query)
for hit in result["hits"]["hits"]:
    print(hit["_source"], "Score:", hit["_score"])

在该查询中,must 部分匹配 title 包含“教程”的文档,而 should 部分计算向量相似度。这种方式可以实现基于文本和向量的多条件搜索。

7. 删除文档和索引


如果需要删除某个文档或整个索引,可以使用以下代码:


删除文档

# 删除文档
es.delete(index="my_index", id=1)

删除索引

# 删除整个索引
es.indices.delete(index="my_index", ignore=[400, 404])

总结


本文详细介绍了使用 Python 与 Elasticsearch 交互的基本操作,包括:

  1. 设置和重置映射(Mapping)
  2. 插入和批量插入文档
  3. 更新已有文档
  4. 基于向量和文本的复合搜索
  5. 删除文档和索引

这些操作基本覆盖了 Elasticsearch 的主要应用场景,能够帮助你熟练地构建、查询和管理索引。在实际应用中,可以根据业务需求调整查询条件与结构,以实现更高效的数据检索和处理。


注意事项


1. 映射设计


  • 提前设计映射:在创建索引时尽可能设计好映射,因为一旦索引创建,映射的字段类型通常无法修改。如果必须修改映射,通常需要删除并重新创建索引。
  • 合理使用字段类型text 类型适合全文检索,keyword 适合精确匹配,dense_vector 则适合存储用于相似度计算的向量。选择合适的字段类型可以显著提升查询性能。
  • 向量维度限制dense_vector 字段的维度(dims 参数)有硬件限制,建议控制在合理范围,通常不要超过 1024 维,以避免内存占用过高。


2. 批量插入


  • 批量操作提升性能:使用 bulk 方法批量插入数据,可以减少网络请求次数,显著提高性能。建议将批量操作的文档数控制在 5000 以内,以避免一次插入的数据过多导致内存溢出。
  • 索引缓冲区设置:在大量插入数据前,可以临时增大 index.refresh_interval,并在插入完成后恢复默认值,从而减少刷新频率,提高插入速度。


3. 更新与删除文档


  • 尽量少用频繁更新:Elasticsearch 的文档更新相当于删除旧文档并插入新文档,因此频繁更新可能导致索引碎片化,影响性能。建议减少更新操作,必要时定期重建索引。
  • 延迟删除:对于一些非实时性强的删除操作,可以考虑批量删除或延迟删除,以减小对性能的影响。


4. 搜索性能


  • 避免使用 match_all:如果索引包含大量数据,match_all 查询会扫描整个索引,影响性能。可以结合过滤条件使用 bool 查询,缩小查询范围。
  • 脚本查询的性能影响:向量相似度计算中用到 script_score,这类脚本查询会消耗更多资源,影响查询性能。可以考虑将常用查询预先计算并缓存。
  • 字段大小限制dense_vector 字段的存储大小和数量会影响索引大小,建议只存储必要的字段并定期优化或重建索引。


5. 索引与数据管理


  • 定期优化与重建索引:长时间使用后,索引可能会产生碎片,影响查询性能。可以定期对索引进行优化或重建,删除过期或无用的数据。
  • 合理的分片设置:在创建索引时设置合理的分片数。对于小数据量,过多的分片会增加管理开销,而大数据量使用少量分片会导致单个分片负载过高。


6. 日志与监控


  • 监控集群状态:定期检查 Elasticsearch 集群的健康状态,包括节点的 CPU、内存使用情况,以及各个索引的查询延迟等,以便及时发现性能瓶颈。
  • 查看错误日志:在插入、查询或更新失败时,检查 Elasticsearch 的错误日志,了解可能的原因,并根据日志信息调整查询结构或索引设置。


7. 安全性


  • 启用认证:在生产环境中,确保启用身份认证和权限控制,避免未经授权的访问。
  • 避免暴露敏感信息:使用 Elasticsearch API 时,确保不将索引结构或敏感数据暴露给外部,必要时加密传输。


8. Python 与 Elasticsearch 兼容性


  • 版本兼容:确保 elasticsearch Python 客户端库的版本与 Elasticsearch 服务器版本兼容,不同版本可能会导致 API 不一致。
  • 连接池管理:对于高并发应用,建议使用连接池来管理与 Elasticsearch 的连接,避免频繁创建和销毁连接导致的性能开销。
评论