Elasticsearch基础:倒排索引与全文搜索

Elasticsearch(ES)是基于Lucene的分布式搜索引擎,核心能力是全文搜索和实时分析。本文从倒排索引讲起,覆盖ES的基本使用。

倒排索引原理

传统数据库用正排索引:给定文档ID -> 获取内容。倒排索引反过来:给定关键词 -> 获取包含该词的文档列表。

假设有两篇文档:

  • Doc1: "Java并发编程指南"
  • Doc2: "Java虚拟机调优"

倒排索引结构:

Term Posting List
java [Doc1, Doc2]
并发 [Doc1]
编程 [Doc1]
指南 [Doc1]
虚拟机 [Doc2]
调优 [Doc2]

搜索"Java调优"时,ES查找"java"和"调优"对应的文档列表,取交集/并集,再根据相关性打分排序。

分词器 (Analyzer)

分词是构建倒排索引的前提。Analyzer由三部分组成:

  1. Character Filter:预处理原始文本(如去除HTML标签)
  2. Tokenizer:将文本切分为词条(token)
  3. Token Filter:对词条做转换(如小写化、去停用词、同义词)

内置分词器:

  • standard:按Unicode分词,适合英文
  • ik_max_word / ik_smart:中文分词插件IK,max_word做最细粒度切分,smart做智能切分

测试分词效果:

POST /_analyze
{
  "analyzer": "ik_smart",
  "text": "Elasticsearch是分布式搜索引擎"
}

Mapping定义

Mapping定义字段类型和索引方式,类似数据库的Schema:

PUT /blog_posts
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "ik_max_word",
        "search_analyzer": "ik_smart"
      },
      "content": {
        "type": "text",
        "analyzer": "ik_max_word"
      },
      "author": {
        "type": "keyword"
      },
      "publish_date": {
        "type": "date",
        "format": "yyyy-MM-dd"
      },
      "tags": {
        "type": "keyword"
      },
      "view_count": {
        "type": "integer"
      }
    }
  }
}
  • text类型会被分词,用于全文搜索
  • keyword类型不分词,用于精确匹配、聚合、排序
  • 一个字段可以同时有text和keyword两种索引(fields多字段特性)

基本CRUD

// 创建文档(指定ID)
PUT /blog_posts/_doc/1
{
  "title": "Elasticsearch入门教程",
  "content": "本文介绍ES的基本概念和使用方法",
  "author": "zhangsan",
  "publish_date": "2021-08-19",
  "tags": ["elasticsearch", "搜索"],
  "view_count": 0
}

// 创建文档(自动生成ID)
POST /blog_posts/_doc
{
  "title": "第二篇文章",
  "content": "...",
  "author": "lisi"
}

// 获取文档
GET /blog_posts/_doc/1

// 更新文档(部分更新)
POST /blog_posts/_update/1
{
  "doc": {
    "view_count": 100
  }
}

// 删除文档
DELETE /blog_posts/_doc/1

Bool查询

Bool查询是ES中最常用的复合查询,由四种子句组成:

POST /blog_posts/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "content": "分布式搜索" } }
      ],
      "should": [
        { "match": { "title": "入门" } }
      ],
      "filter": [
        { "term": { "author": "zhangsan" } },
        { "range": { "publish_date": { "gte": "2021-01-01" } } }
      ],
      "must_not": [
        { "term": { "tags": "deprecated" } }
      ]
    }
  }
}
  • must:必须匹配,参与评分
  • should:可选匹配,匹配则加分
  • filter:必须匹配,不参与评分(性能更好,会被缓存)
  • must_not:必须不匹配

经验法则:需要相关性评分的条件放must/should,只做过滤的条件放filter。

聚合 (Aggregations)

聚合相当于SQL的GROUP BY + 聚合函数:

POST /blog_posts/_search
{
  "size": 0,
  "aggs": {
    "by_author": {
      "terms": {
        "field": "author",
        "size": 10
      },
      "aggs": {
        "avg_views": {
          "avg": { "field": "view_count" }
        }
      }
    },
    "monthly_posts": {
      "date_histogram": {
        "field": "publish_date",
        "calendar_interval": "month"
      }
    }
  }
}
  • terms聚合:按字段值分组
  • date_histogram:按时间区间分组
  • 聚合可以嵌套,实现多维度分析

ES的核心优势在于:倒排索引提供极快的全文搜索,加上分布式架构支持海量数据,再配合聚合能力做实时分析——这是传统关系数据库难以兼顾的。