面包屑图标 当前位置: 首页
AI资讯
热点详情

ES结合BM25实现高效文档检索

AI热点日报
AI热点日报时间:2026-06-05
热点解读

在信息爆炸的今天,如何从海量数据中快速捞取最有价值的信息,几乎是每个技术团队都在面对的硬仗。Elasticsearch(简称 ES)凭借其分布式架构和高可用特性,在全文检索领域早已是明星选手。而它默认搭载的相关性评分算法 BM25,则是让搜索结果真正“排好队”的关键。这篇文章会从一个极简的例子切入,

在信息爆炸的今天,如何从海量数据中快速捞取最有价值的信息,几乎是每个技术团队都在面对的硬仗。Elasticsearch(简称 ES)凭借其分布式架构和高可用特性,在全文检索领域早已是明星选手。而它默认搭载的相关性评分算法 BM25,则是让搜索结果真正“排好队”的关键。这篇文章会从一个极简的例子切入,带你一步步搞懂 ES 的倒排索引到底是怎么工作的,BM25 又是如何给搜索结果打出分数、排好顺序的。

ES × BM25:打造高效文档检索的秘密

先说说几个核心判断:ES 能这么快,靠的无非两件事——倒排索引和相关性算法。倒排索引负责把文档里的词拆开,建立起“词 → 文档”的快速查找表;而 BM25 则用一套统计模型,对匹配上的文档进行排序打分。两者结合,效果才够“聪明”。

1. 初识 Elasticsearch 与文档检索

Elasticsearch 是一个分布式搜索和分析引擎,在日志分析、全文检索、业务监控这些场景里很常见。它能从海量数据中快速检索出关键信息,核心竞争力其实就两个:

  1. 用倒排索引来管理文档内容。
  2. 用高效的相关性算法(默认是 BM25)对匹配文档排序。

全文检索 这一点和传统数据库有很大区别。传统数据库做模糊查询,常常要全表扫描,又慢又耗资源。ES 更适合处理非结构化或半结构化数据,比如自然语言、日志信息,通过分词、倒排索引和基于统计的算法,能快速从大量文本中找到最相关的文档。

2. 倒排索引:搜索引擎的“读心术”

传统关系型数据库里,如果要做一个模糊查询,比如 LIKE '%keyword%',往往是全表扫描,这种方式效率很低。搜索引擎为此发明了“倒排索引”这种结构,极大提升了查询速度。

2.1. 什么是倒排索引?

倒排索引的核心思路很直接:

  • 把文档里的词语拆分(分词)并进行标准化处理。
  • 记录“词语 → 出现在哪些文档、在哪些位置”。

可以这样类比:

  • 正排索引更像是“文档 → 包含的词语”。
  • 倒排索引则是“词语 → 出现的文档列表”。

这样一来,要查找包含某个词语的文档,只需从索引中直接定位,无需遍历所有文档,速度自然快得多。

3. 示例:搭建小型倒排索引

拿一个极简的例子来说明倒排索引的构建过程。假设有下面这 3 个文档:

Doc1: "Elasticsearch is a powerful search engine"
Doc2: "Elasticsearch is used for full-text search"
Doc3: "Search engines are powerful tools"

第一步:分词与标准化

ES 内置的分词器(如 Standard Analyzer)会对文档进行分词,并做一些常见处理,比如去除大小写、停用词、词干提取等。这里假设分词后的结果是:

  • Doc1: ["elasticsearch", "is", "a", "powerful", "search", "engine"]
  • Doc2: ["elasticsearch", "is", "used", "for", "full", "text", "search"]
  • Doc3: ["search", "engines", "are", "powerful", "tools"]

第二步:构建倒排索引

把每个词语出现在哪些文档、以及什么位置记录下来,就得到一张倒排索引表:

词语文档ID位置
elasticsearchDoc1, Doc2Doc1:[0], Doc2:[0]
isDoc1, Doc2Doc1:[1], Doc2:[1]
aDoc1Doc1:[2]
powerfulDoc1, Doc3Doc1:[3], Doc3:[3]
searchDoc1, Doc2, Doc3Doc1:[4], Doc2:[6], Doc3:[0]
engineDoc1Doc1:[5]
usedDoc2Doc2:[2]
forDoc2Doc2:[3]
fullDoc2Doc2:[4]
textDoc2Doc2:[5]
enginesDoc3Doc3:[1]
areDoc3Doc3:[2]
toolsDoc3Doc3:[4]

有了这张表,每一步查询都变得简单直接。

4. 查询流程:从键入关键字到获取结果

当用户输入查询词,比如 “powerful search” 时,ES 是怎么处理的?

  1. 对查询进行分词和标准化
    把查询词同样处理,得到 ["powerful", "search"]。

  2. 在倒排索引中查找
    “powerful” 出现在 Doc1、Doc3;
    “search” 出现在 Doc1、Doc2、Doc3;
    综合候选文档就是 Doc1、Doc2、Doc3。

  3. 计算相关性分数(BM25)
    这几篇文档都匹配上了,但哪一篇最相关?这时候 BM25 就派上用场了。

  4. 根据评分排序并返回
    最后按分值从高到低排序,返回给用户。

5. BM25:背后的数学公式

BM25(Best Matching 25)是一套用于计算“文档与查询”匹配度的打分函数。它的核心公式简化后如下:

公式中涉及的几个关键变量:

  • qi 表示查询中的某个单词。
  • f(qi, D) 表示单词 qi 在文档 D 中间出现的次数(词频)。
  • IDF(qi) 表示单词 qi 的逆文档频率,反映这个词在所有文档中“有多稀有”。其常见计算公式为:IDF = log( (N - n(qi) + 0.5) / (n(qi) + 0.5) + 1 ),其中 N 是文档总数,n(qi) 是包含该词的文档数。
  • |D| 表示文档 D 的长度(词数)。
  • a vgdl 表示所有文档的平均长度。
  • k1 和 b 是可调参数,通常取 k1=1.2,b=0.75,用来控制词频和文档长度对评分的影响。

简单来说,BM25 在考虑一个词的稀有程度(IDF)和在文档中间出现的次数(TF)的同时,还引入了文档长度来做平衡。分数越高,代表该文档越符合用户的查询意图。

6. BM25 计算示例:深度解析

回到前面的例子,我们实际算一下 “powerful search” 的评分。

1. 统计信息

  • 文档总数:3
  • 包含词 "powerful" 的文档数:2(Doc1, Doc3)
  • 包含词 "search" 的文档数:3(Doc1, Doc2, Doc3)

2. 计算 IDF

IDF("powerful") = log( (3 - 2 + 0.5) / (2 + 0.5) + 1 ) = log(1.5 / 2.5 + 1) ≈ log(1.6) ≈ 0.470
IDF("search") = log( (3 - 3 + 0.5) / (3 + 0.5) + 1 ) = log(0.5 / 3.5 + 1) ≈ log(1.1429) ≈ 0.1335

3. 计算文档长度与平均长度

  • Doc1: 6 个词
  • Doc2: 7 个词
  • Doc3: 5 个词
  • 平均长度 a vgdl = (6 + 7 + 5) / 3 = 6

4. 逐文档计算 BM25

假设 k1 = 1.2,b = 0.75。

Doc1: "Elasticsearch is a powerful search engine"

  • "powerful" 的 TF = 1
  • "search" 的 TF = 1

文档长度 |D| = 6,|D|/a vgdl = 6/6 = 1
BM25(Doc1) = 0.470 × (1.2 × 1) / (1 + 1.2 × (1 - 0.75 + 0.75 × 1)) + 0.1335 × (1.2 × 1) / (1 + 1.2 × (1 - 0.75 + 0.75 × 1))
= 0.470 × 1.2 / (1 + 1.2 × 1) + 0.1335 × 1.2 / (1 + 1.2 × 1)
= (0.470 + 0.1335) × 1.2 / 2.2
= 0.6035 × 0.5455 ≈ 0.3292

(注意:这里计算保留小数的精度与原文略有差异,但最终排序结果一致。)

Doc2: "Elasticsearch is used for full-text search"

  • "powerful" 的 TF = 0
  • "search" 的 TF = 1

文档长度 |D| = 7,|D|/a vgdl = 7/6 ≈ 1.1667
BM25(Doc2) = 0 + 0.1335 × (1.2 × 1) / (1 + 1.2 × (1 - 0.75 + 0.75 × 1.1667))
= 0.1335 × 1.2 / (1 + 1.2 × (0.25 + 0.875))
= 0.1602 / (1 + 1.2 × 1.125)
= 0.1602 / (1 + 1.35) ≈ 0.0682

Doc3: "Search engines are powerful tools"

  • "powerful" 的 TF = 1
  • "search" 的 TF = 1

文档长度 |D| = 5,|D|/a vgdl = 5/6 ≈ 0.8333
BM25(Doc3) = 0.470 × 1.2 / (1 + 1.2 × (1 - 0.75 + 0.75 × 0.8333)) + 0.1335 × 1.2 / (1 + 1.2 × (1 - 0.75 + 0.75 × 0.8333))
= (0.470 + 0.1335) × 1.2 / (1 + 1.2 × (0.25 + 0.625))
= 0.6035 × 1.2 / (1 + 1.2 × 0.875)
= 0.7242 / (1 + 1.05) ≈ 0.3532

5. 最终排序

  • Doc3:0.3532
  • Doc1:0.3292
  • Doc2:0.0682

结果很清楚:Doc3 在这个查询场景下得分最高,Doc1 次之,Doc2 排在最末。

7. 总结

Elasticsearch 之所以能在海量数据中快速找到最相关的文档,主要抓住了这些关键点:

  1. 倒排索引:把文档中的单词拆分出来,建成索引结构,从而实现高效搜索。
  2. 查询分词:用户输入也要经过同样的分词处理,匹配和打分才能更精准。
  3. BM25 算法:通过词频、逆文档频率、文档长度等要素,给匹配的文档打出一个综合分数,反映其与查询的“匹配度”。

8. ES实战

8.1 安装与配置ES

接下来是动手环节。先安装并启动 Elasticsearch,步骤如下:

  1. 下载ES
# 下载ES 8.x版本
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.x.x-linux-x86_64.tar.gz

# 解压
tar -xzf elasticsearch-8.x.x-linux-x86_64.tar.gz

# 进入ES目录
cd elasticsearch-8.x.x/
  1. 修改配置编辑 config/elasticsearch.yml
# 集群名称
cluster.name: my-es-cluster

# 节点名称
node.name: node-1

# 数据和日志存储路径
path.data: /path/to/data
path.logs: /path/to/logs

# 网络设置
network.host: 0.0.0.0
http.port: 9200

# 开发环境设置
discovery.type: single-node
  1. 启动ES
# 启动
./bin/elasticsearch

# 检查是否启动成功
curl http://localhost:9200

8.2 创建索引并定义映射

创建一个用于存储文章的索引:

PUT /articles
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 1,
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "stop",
            "snowball"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "my_analyzer",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      },
      "content": {
        "type": "text",
        "analyzer": "my_analyzer"
      },
      "author": {
        "type": "keyword"
      },
      "publish_date": {
        "type": "date"
      }
    }
  }
}

8.3 索引文档

插入一些测试数据:

POST /articles/_doc/1
{
  "title": "Elasticsearch Guide",
  "content": "Elasticsearch is a powerful search engine based on Lucene",
  "author": "John Doe",
  "publish_date": "2024-03-15"
}

POST /articles/_doc/2
{
  "title": "Advanced Search Techniques",
  "content": "Learn how to use BM25 algorithm for better search results",
  "author": "Jane Smith",
  "publish_date": "2024-03-16"
}

POST /articles/_doc/3
{
  "title": "Understanding Text Analysis",
  "content": "Text analysis is crucial for search engine performance",
  "author": "Mike Johnson",
  "publish_date": "2024-03-17"
}

8.4 查询示例

  1. 简单全文搜索
GET /articles/_search
{
  "query": {
    "match": {
      "content": "search engine"
    }
  }
}
  1. 多字段搜索
GET /articles/_search
{
  "query": {
    "multi_match": {
      "query": "search engine",
      "fields": ["title", "content"]
    }
  }
}
  1. 使用bool查询组合多个条件
GET /articles/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "content": "search"
          }
        }
      ],
      "should": [
        {
          "match": {
            "title": "elasticsearch"
          }
        }
      ],
      "filter": [
        {
          "range": {
            "publish_date": {
              "gte": "2024-03-15"
            }
          }
        }
      ]
    }
  }
}

8.5 分析搜索结果

执行搜索请求后,ES 会返回带有相关性分数的结果:

{
  "took": 5,
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 1.3862944,
    "hits": [
      {
        "_index": "articles",
        "_id": "1",
        "_score": 1.3862944,
        "_source": {
          "title": "Elasticsearch Guide",
          "content": "Elasticsearch is a powerful search engine based on Lucene"
        }
      },
      {
        "_index": "articles",
        "_id": "2",
        "_score": 0.9530659,
        "_source": {
          "title": "Advanced Search Techniques",
          "content": "Learn how to use BM25 algorithm for better search results"
        }
      }
    ]
  }
}

8.6 调优搜索相关性

  1. 自定义评分
GET /articles/_search
{
  "query": {
    "script_score": {
      "query": {
        "match": {
          "content": "search engine"
        }
      },
      "script": {
        "source": "_score * (doc['publish_date'].value.millis - 1710000000000) / 86400000"
      }
    }
  }
}
  1. 调整字段权重
GET /articles/_search
{
  "query": {
    "multi_match": {
      "query": "search engine",
      "fields": [
        "title^3",
        "content"
      ]
    }
  }
}

8.7 性能优化建议

  1. 合理设置分片数

    • 单个分片大小建议在20GB-40GB之间
    • 分片数 = 数据总量 / 单个分片大小
  2. 使用合适的映射

    • 对于不需要分词的字段用 keyword 类型
    • 对于需要分词的字段用 text 类型
    • 合理使用 fields 设置多字段映射
  3. 优化内存使用

    • 设置合适的JVM堆大小
    • 使用 doc_valuesfielddata 优化聚合性能
  4. 查询优化

    • 尽量用过滤器(filter)代替查询(query)
    • 避免使用通配符查询
    • 合理利用缓存

接下来,再聊聊 Docker 化安装 ES 以及一些界面化管理的工具。

9. Docker化安装ES

9.1 安装单节点ES

  1. 创建docker-compose.yml文件
version: '3'
services:
  elasticsearch:
    image: elasticsearch:8.11.1
    container_name: elasticsearch
    environment:
      - discovery.type=single-node
      - ES_JA VA_OPTS=-Xms512m -Xmx512m
      - xpack.security.enabled=false
    volumes:
      - ./es/data:/usr/share/elasticsearch/data
      - ./es/plugins:/usr/share/elasticsearch/plugins
    ports:
      - "9200:9200"
      - "9300:9300"
    networks:
      - elastic
    
networks:
  elastic:
    driver: bridge
  1. 启动ES
# 创建目录
mkdir -p ./es/data ./es/plugins

# 设置目录权限
chmod 777 ./es/data ./es/plugins

# 启动容器
docker-compose up -d
  1. 验证安装
# 检查容器状态
docker ps

# 测试ES是否正常运行
curl http://localhost:9200

9.2 安装Kibana(官方可视化工具)

  1. 更新docker-compose.yml,添加Kibana服务
version: '3'
services:
  elasticsearch:
    # ... ES配置保持不变 ...

  kibana:
    image: kibana:8.11.1
    container_name: kibana
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch
    networks:
      - elastic

networks:
  elastic:
    driver: bridge
  1. 启动Kibana
docker-compose up -d

访问 http://localhost:5601 就能打开 Kibana 界面。

9.3 安装Elasticsearch-head(轻量级可视化工具)

version: '3'
services:
  elasticsearch:
    # ... ES配置保持不变 ...

  elasticsearch-head:
    image: mobz/elasticsearch-head:5
    container_name: elasticsearch-head
    ports:
      - "9100:9100"
    networks:
      - elastic

访问 http://localhost:9100 即可使用 elasticsearch-head。

10 可视化工具对比

10.1 Kibana(官方工具)

优点:

  • 功能最完整
  • 与ES版本完全兼容
  • 支持复杂的数据可视化
  • 支持开发工具控制台
  • 支持安全认证

主要功能:

  1. Dev Tools

    • 提供交互式控制台
    • 支持自动补全
    • 支持多请求组合
  2. Index Management

    • 索引创建和管理
    • 映射配置
    • 索引模板管理
  3. 数据可视化

    • 支持多种图表类型
    • 可创建仪表板
    • 实时数据监控

10.2 Elasticsearch-head

优点:

  • 界面简洁
  • 启动快速
  • 资源占用少
  • 适合简单操作

主要功能:

  1. 集群监控

    • 查看集群状态
    • 节点信息
    • 索引状态
  2. 数据浏览

    • 查看索引数据
    • 简单的增删改查
    • JSON格式化显示
  3. REST请求

    • 简单的REST客户端
    • 支持基本查询

10.3 Cerebro(另一个选择)

添加Cerebro到docker-compose.yml:

version: '3'
services:
  # ... 其他服务配置 ...

  cerebro:
    image: lmenezes/cerebro:0.9.4
    container_name: cerebro
    ports:
      - "9000:9000"
    networks:
      - elastic

优点:

  • 现代化界面
  • 支持多集群管理
  • 操作简单直观

主要功能:

  1. 集群管理

    • 多集群监控
    • 节点状态查看
    • 分片分配可视化
  2. 索引管理

    • 创建/删除索引
    • 管理别名
    • 查看索引设置
  3. REST API

    • 内置REST客户端
    • 请求历史记录
    • 响应格式化

11. 推荐使用方案

  1. 开发环境

    • Kibana + Elasticsearch-head
    • Kibana用于复杂操作和可视化
    • Elasticsearch-head用于快速查看数据
  2. 生产环境

    • 主要使用Kibana
    • 配置适当的安全认证
    • 根据需要开放必要的功能
  3. 配置建议

version: '3'
services:
  elasticsearch:
    image: elasticsearch:8.11.1
    container_name: elasticsearch
    environment:
      - discovery.type=single-node
      - ES_JA VA_OPTS=-Xms512m -Xmx512m
      - xpack.security.enabled=false
    volumes:
      - ./es/data:/usr/share/elasticsearch/data
      - ./es/plugins:/usr/share/elasticsearch/plugins
    ports:
      - "9200:9200"
    networks:
      - elastic
    
  kibana:
    image: kibana:8.11.1
    container_name: kibana
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch
    networks:
      - elastic

  elasticsearch-head:
    image: mobz/elasticsearch-head:5
    container_name: elasticsearch-head
    ports:
      - "9100:9100"
    networks:
      - elastic

networks:
  elastic:
    driver: bridge

用这套配置,就能同时拥有 Kibana 和 Elasticsearch-head 的能力,既能做复杂的数据分析和可视化,也能快速查看集群状态和数据。

热点追踪提示词
你是一名 AI 行业编辑,请围绕下面这条热点输出一份资讯解读:
热点:ES结合BM25实现高效文档检索要求:
1. 先用一句话解释这条热点在讲什么
2. 再总结它为什么重要
3. 说明会影响哪些 AI 产品或内容方向
4. 最后给出 3 个适合资讯站使用的标题
来源:https://www.53ai.com/news/zhinenghuagaizao/2025033039017.html
ai 人工智能

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

相关热点
AI热点2026-07-17 16:46
元宝AI:LLM与微信搜索深度整合的智能问答助手

说到底,对于AI助手而言,数据质量就是“水源”和“土壤”。微信搜索积累的那套海量且可信的高质量数据,恰好给了元宝最稀缺的养料。元宝团队也确实没浪费这个优势——回答质量在线、响应速度快得不像常规的AI产品、信息还够新鲜,UI交互也做得够克制够简洁,再加上那个智能体商店的生态布局,怎么说呢,鹅厂这一波,

AI热点2026-07-17 16:46
并非所有AI都是生成式AI

近年来,生成式AI确实吸引了大量关注——从自动撰写文章到凭空生成图像,它几乎成了“人工智能”的代名词。但若仔细审视,生成式AI仅仅是人工智能这棵大树上的一个分支,远非全貌。将整个AI领域等同于生成式AI,就像把智能手机等同于整个移动通信产业,未免有失偏颇。事实上,“生成式AI”这个词汇承载了过多期待

AI热点2026-07-17 16:46
通义千问2能否超越LLama3?在A5000 GPU上的性能实测对比分析

在NVIDIAA5000GPU上,Ollama运行Qwen2-7B模型推理流畅,代码质量高。Qwen2-72B在多项基准测试中超越Llama3-70B,其7B版本在编码和中文指标上表现优异,接近GPT-4水平。

AI热点2026-07-17 16:46
不必关心大模型但要了解与你相关的AI智能体

苹果WWDC发布AppleIntelligence,将Siri升级为能理解自然语言、跨APP执行复杂任务的智能体。智能体作为数字员工可主动决策,是AI新方向。中美发展接近,中国在落地应用和硬件集成上有优势。智能体赋能私域需先进行思维转变,基于企业数据构建专属数字员工。

延伸阅读