使用 Elasticsearch 构建搜索引擎

1. Elasticsearch 简介

Elasticsearch 是一个基于 Apache Lucene™ 构建的开源分布式搜索引擎,提供强大的全文搜索和分析能力。它不仅是搜索引擎,还具有以下特性:

  • 分布式实时文档存储,支持字段索引与搜索
  • 实时分析引擎
  • 可扩展至上百个节点,支持 PB 级结构化/非结构化数据

主要应用场景:

  • 企业级搜索
  • 日志分析
  • 业务数据分析
  • 安全分析

2. 核心概念

2.1 节点与集群

  • 节点(Node): 单个 Elasticsearch 实例
  • 集群(Cluster): 一组协同工作的节点

2.2 索引(Index)

相当于关系型数据库中的"数据库"概念:

  • 顶层数据管理单位
  • 名称必须小写
  • 包含多个文档

2.3 文档(Document)

相当于数据库中的"记录":

  • JSON 格式的数据单元
  • 同一索引中文档结构可以不同(但建议保持一致)

2.4 类型(Type) [已弃用]

在 7.x 版本中已被移除,现在每个索引只包含单一类型。

2.5 字段(Field)

文档中的键值对,相当于数据库中的列。

3. 环境准备

3.1 安装 Elasticsearch

推荐使用 Docker 安装最新版本:

docker pull docker.elastic.co/elasticsearch/elasticsearch:8.12.0
docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:8.12.0

3.2 安装 Python 客户端

pip install elasticsearch

4. 基本操作

4.1 创建索引

from elasticsearch import Elasticsearch

# 连接本地 Elasticsearch
es = Elasticsearch("http://localhost:9200")

# 创建索引
mapping = {
    "mappings": {
        "properties": {
            "title": {"type": "text", "analyzer": "ik_max_word"},
            "url": {"type": "keyword"}
        }
    }
}

response = es.indices.create(index="news", body=mapping, ignore=400)
print(response)

4.2 删除索引

response = es.indices.delete(index="news", ignore=[400, 404])
print(response)

5. 文档操作

5.1 插入数据

doc = {
    "title": "高考圆梦:中国学生成功考入理想大学",
    "url": "http://example.com/1"
}

# 方法1:指定ID
res = es.create(index="news", id=1, body=doc)

# 方法2:自动生成ID
res = es.index(index="news", body=doc)

5.2 更新数据

updated_doc = {
    "title": "高考圆梦:中国学生成功考入理想大学",
    "url": "http://example.com/1",
    "date": "2023-06-10"
}

res = es.update(index="news", id=1, body={"doc": updated_doc})

5.3 删除数据

res = es.delete(index="news", id=1)

6. 搜索功能

6.1 简单查询

# 查询所有文档
res = es.search(index="news", body={"query": {"match_all": {}}})
print(res['hits']['hits'])

6.2 全文检索

query = {
    "query": {
        "match": {
            "title": "中国 高考"
        }
    }
}

res = es.search(index="news", body=query)
for hit in res['hits']['hits']:
    print(hit['_source']['title'], hit['_score'])

6.3 高级查询

# 布尔查询
bool_query = {
    "query": {
        "bool": {
            "must": [
                {"match": {"title": "中国"}}
            ],
            "should": [
                {"match": {"title": "高考"}},
                {"match": {"title": "大学"}}
            ],
            "filter": [
                {"range": {"date": {"gte": "2023-01-01"}}}
            ]
        }
    }
}

res = es.search(index="news", body=bool_query)

7. 中文分词

Elasticsearch 需要安装 IK 分词插件:

# 使用 Docker 安装插件
docker exec -it <container_id> /bin/bash
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v8.12.0/elasticsearch-analysis-ik-8.12.0.zip

8. 最佳实践

  1. 索引设计:

    • 合理设置分片数(建议每个分片20-40GB)
    • 使用别名管理索引
  2. 性能优化:

    • 避免大文档(>100MB)
    • 使用批量操作(bulk API)
    • 合理使用缓存
  3. 安全设置:

    • 启用 HTTPS
    • 配置认证
    • 设置访问控制

9. 总结

Elasticsearch 提供了强大的搜索和分析能力,结合 Python 客户端可以轻松实现各种搜索功能。在实际应用中,还需要考虑集群管理、性能优化和安全等方面的问题。

10. 扩展学习