1、Elasticsearch是什么

1.1概念:

Elasticsearch是由Java语言开发基于Lucene的一款开源的搜索、聚合分析和存储引擎。同时它也可以称作是一种非关系型文档数据库。

1.2特点:
  • 天生分布式、高性能(PB级)、高可用、易扩展、易维护。
  • 跨语言、跨平台:几乎支持所有主流编程语言,并且支持在“"Linux、Windows、MacOS”多平台部署
  • 支持结构化、非结构化、地理位置搜索等
1.3适用场景:

海量数据的全文检索,搜索引擎、垂直搜索、站内搜索:

  • 百度、知乎、微博、CSDN
  • 导航、外卖、团购等软件
  • 以京东、淘宝为代表的垂直搜索
  • B站、抖音、爱奇艺、QQ音乐等音视频软件
  • 数据分析和聚合查询
  • 日志系统:ELK

2、mapping是什么,你知道es哪些数据类型?

2.1概念:

ES中的mapping有点类似与RDB中“表结构”的概念,在MySQL中,表结构里包含了字段名称,字段的类型还有索引信息等。在Mapping.里也包含了一些属性,比如字段名称、类型、字段使用的分词器、是否评分、是否创建索引等属性,并且在ES中一个字段可以有对个类型。分词器、评分等概念在后面的课程讲解。
定义是以json文档存储的

2.2ES数据类型

2.2.1常见类型

  1. 数据类型:long integer short byte double float half float scaled float unsigned_long
  2. Keywords:
    1. keyword:适用于索引结构化的字段,可以用于过滤、排序、聚合。keyword类型的字段只能通过精确值(exact value)搜索到。Id应该用keyword.keyword字段通常用于排序,汇总Term查询,例如term.
    2. constant keyword:始终包含相同值的关键字字段
    3. wildcard:可针对类似grep的通配符查询优化日志行和类似的关键字值
  3. dates(时间类型):包括date和date nanos,
  4. alias:为现有字段定义别名。
  5. text:当一个字段是要被全文搜索的,比如Email内容、产品描述,这些字段应该使用text类型。设置text类型以后,字段内容会被分析,在生成倒排索引以前,字符串会被分析器分成一个一个词项。text类型的字段不用于排序,很少用于聚合。(解释一下为啥不会为txt创建正排索引:大量堆空间,尤其是在加载高基数txt字段时。字段数据一旦加载到堆中,就在该段的生命周期内保持在那里。同样,加载字段数据是一个昂贵的过程,可能导致用户遇到延迟问题。这就是默认情况下禁用字段数据的原因)

2.2.2对象关系类型

  1. object:用于单个JSON对象
  2. nested:用于JSON对象数组
  3. join:为同一索引中的文档定义父/子关系。

2.2.3结构化类型

  1. geo-point:纬度/经度积分
  2. geo-shape:用于多边形等复杂形状
  3. point:笛卡尔坐标点
  4. shape:笛卡尔任意几何图形
2.3自动映射和手工映射

2.3.1 Dynamic field mapping:

输入类型 映射类型
整数 long
浮点数 float
true 、false boolean
日期 date
数组 取决于数组中的第一个有效值
对象 object
字符串 如果不是数字和日期类型,那会被映射为text和keyword两个类型除了上述字段类型之外,其他类型都必须显示映射,也就是必须手工指定,因为其他类型E$无法自动识别。

2.3.2 手动映射

PUT /product_index
{
  "settings": {
    "number_of_shards": 1,   // 分片数
    "number_of_replicas": 0  // 副本数(演示用0)
  },
  "mappings": {
    "properties": {
      "product_id": {
        "type": "keyword"  // 精确匹配/聚合
      },
      "name": {
        "type": "text",    // 全文搜索
        "fields": {
          "keyword": {     // 子字段用于精确匹配
            "type": "keyword"
          }
        }
      },
      "price": {
        "type": "float"    // 浮点数
      },
      "description": {
        "type": "text"     // 长文本搜索
      },
      "created_at": {
        "type": "date",    // 日期
        "format": "yyyy-MM-dd HH:mm:ss"
      },
      "tags": {
        "type": "keyword"  // 标签数组(自动处理)
      },
      "location": {
        "type": "geo_point" // 经纬度坐标
      },
      "is_available": {
        "type": "boolean"  // 布尔值
      }
    }
  }
}

  • text 类型会被分词,适合全文搜索。
  • keyword 类型不分词,适合精确匹配/聚合。
  • 日期类型需指定格式(如不指定,ES 会尝试自动解析)。
2.4参数映射

以下是 Elasticsearch 中常见的映射参数详解(带示例说明),这些参数用于精确控制字段的行为:


一、核心字段类型参数

  1. type

    • 定义字段数据类型
    • 值:text, keyword, long, integer, float, boolean, date, geo_point
    "price": { "type": "float" }
    
    
  2. index

    • 是否创建倒排索引(即是否可搜索)
    • 值:true(默认)或 false
    "product_id": { 
      "type": "keyword",
      "index": false  // 此字段无法被搜索
    }
    
    
  3. doc_values

    • 是否启用列式存储(用于排序/聚合)
    • 值:true(默认)或 false
    "tags": {
      "type": "keyword",
      "doc_values": false  // 禁止聚合排序
    }
    
    

二、文本专用参数

  1. analyzer

    • 指定索引分词器
    "description": {
      "type": "text",
      "analyzer": "english"  // 使用英文分词器
    }
    
    
  2. search_analyzer

    • 指定搜索时使用的分词器
    "description": {
      "type": "text",
      "analyzer": "standard",
      "search_analyzer": "simple"
    }
    
    
  3. fields

    • 创建多字段(Multi-Fields)
    "name": {
      "type": "text",
      "fields": {
        "keyword": { "type": "keyword" }  // 新增子字段
      }
    }
    
    

三、数值/日期专用参数

  1. coerce

    • 是否自动转换数据类型
    • 值:true(默认)或 false
    "quantity": {
      "type": "integer",
      "coerce": false  // 禁止"10"转10
    }
    
    
  2. format(日期字段)

    • 指定日期格式
    "created_at": {
      "type": "date",
      "format": "yyyy-MM-dd HH:mm:ss||epoch_millis"
    }
    
    

四、特殊行为参数

  1. copy_to

    • 将字段值复制到目标字段
    "first_name": {
      "type": "text",
      "copy_to": "full_name"
    },
    "last_name": {
      "type": "text",
      "copy_to": "full_name"
    }
    
    
  2. ignore_above(keyword专用)

    • 超过指定长度的字符串不索引
    "serial_number": {
      "type": "keyword",
      "ignore_above": 50  // 超50字符忽略
    }
    
    
  3. null_value

    • 替换null值的默认值
    "rating": {
      "type": "integer",
      "null_value": -1
    }
    
    

五、对象关系参数

  1. dynamic

    • 控制未定义字段的动态映射行为
    "mappings": {
      "dynamic": "strict",  // 禁止自动新增字段
      "properties": {...}
    }
    
    
    • 值:true(自动)| false(忽略)| strict(拒绝)
  2. properties

    • 定义嵌套字段结构
    "address": {
      "type": "object",
      "properties": {
        "city": { "type": "keyword" }
      }
    }
    
    

六、地理空间参数

  1. ignore_malformed

    • 是否忽略错误格式的数据
    "location": {
      "type": "geo_point",
      "ignore_malformed": true  // 跳过非法坐标
    }
    
    

重要参数对比表

参数 适用类型 默认值 使用场景
index 所有类型 true 禁用搜索(如敏感字段)
doc_values 除text外 true 禁用排序/聚合
fields text - 实现精准搜索+全文搜索
copy_to text/keyword - 跨字段搜索
coerce 数值/日期 true 防止类型污染
dynamic mapping根级 true 控制未知字段行为
ignore_above keyword 2147483647 避免长字符串浪费资源

使用技巧

  1. 性能优化

    "log_message": {
      "type": "text",
      "index": false,       // 禁止搜索
      "doc_values": false    // 禁止聚合
    }
    
    
  2. 精细化文本处理

    "content": {
      "type": "text",
      "analyzer": "ik_smart",
      "fields": {
        "english": { 
          "type": "text",
          "analyzer": "english"
        }
      }
    }
    
    
  3. 日期兼容性处理

    "event_time": {
      "type": "date",
      "format": "strict_date_optional_time||epoch_millis"
    }
    
    

合理组合这些映射参数,能显著提升搜索性能和存储效率。建议通过 GET /index_name/_mapping 命令随时验证映射配置。

3.什么是全文检索

3.1相关度

  • 搜索:有明确的查询边界

  • 检讲究相关度,无明确的查询条件边界

3.2图解全文检索

ES中数据存储是以倒排索引去存储:倒排索引:词项到词项表之间的映射关系

主要有4步

  • 切词:核心是分词器来对其文本内容来划分单独的小块,一个个都词项
  • 规范化:大小写统一没有词缀等
  • 去重
  • 字典序:按照字典字母的顺序 映射到词项字典中
    在这里插入图片描述

当用户搜索的时候,会按照搜索的关键词进行分词:与词项表中的都词项进行匹配,拿到的对应的映射id,匹配度越高,相关度也就越高;那么也将优先在用户的查询列表中展示。

在这里插入图片描述

4.ES支持哪些类型查询

查询类型 使用场景 是否影响评分 性能建议
term/range 精确值匹配、范围过滤 ✅ 优先用于filter
match 全文搜索 需优化分词器
bool+filter 组合过滤条件 ⚡️ 高性能首选
nested 嵌套对象搜索 🔥 慎用(性能差)
knn AI向量搜索 需硬件加速
{
  "bool": {
    "must": [ { "match": { "title": "search" } } ],
    "filter": [ { "term": { "status": "active" } } ],
    "should": [
      { "match": { "content": "cloud" } },
      { "range": { "likes": { "gt": 100 } } }
    ],
    "minimum_should_match": 1 // 至少满足1个should条件
  }
}

组合查询

bool:可以组合多个查询条件,bool查询也是采用more matches is better的机制,因此满足must和should子句的文档将会合并起来计算分值

  • must:必须满足子句(查询)必须出现在匹配的文档中,并将有助于得分。
  • filter:过滤器不计算相关度分数,cache☆子句(查询)必须出现在匹配的文档中。但是不像must查询的分数将被忽略。Filter子句在filter上下文中执行,这意味着计分被忽略,并且子句被考虑用于缓存。
  • should:可能满足or子句(查询)应出现在匹配的文档中。
  • must not:必须不满足不计算相关度分数not子句(查询)不得出现在匹配的文档中。子句在过滤器上下
    文中执行,这意味着计分被忽略,并且子句被视为用于缓存。由于忽略计分,0因此将返回所有文档的分数。
  • minimum should match:参数指定should返回的文档必须匹配的子句的数量或百分比。如果bool查询包含至少一个should子句,而没有must或filter子句,则默认值为1。否则,默认值为0

5、term、match、keyword的有何区别,你还知道哪些检索类型

5.1term和match

在这里插入图片描述

term:对搜索词不分词,不影响源数据,会直接拿该词汇去查询
match:对搜索词分词,不影响源数据
可以使用判断是否是最细粒度的分词

get _analyze{
   "text":"xiao phone"
}

5.2term和keyword

term:检索类型

  • 在倒排索引中进行精确值匹配
  • 对输入值不进行分词处理(原样搜索)
  • 主要用于搜索 keyword/numeric/boolean 等类型字段

keyword:字段类型

  • 核心特性

    • 数据不被分词(完整保留原始值)
    • 用于精确匹配(如 ID、状态码、标签)和聚合操作
    • 默认生成 doc_values(优化聚合/排序性能)

    在这里插入图片描述

// 方案1:使用 .keyword 子字段
GET /books/_search
{
  "query": {
    "term": {
      "title.keyword": "Elastic Guide" // 命中完整书名
    }
  }
}

// 方案2:改用 match 查询(支持分词搜索)
GET /books/_search
{
  "query": {
    "match": { 
      "title": "Elastic Guide" // 匹配分词后的单词
    }
  }
}

6、什么是开发模式和什么是生产模式

开发模式:开发模式是默认配置(未配置集群发现设置),如果用户只是出于学习目的,而引导检查会把很多用户挡在门外,所以ES提供了一个设置项 discovery.type=single-node。此项配置为指定节点为单节点发现以绕过引导检查。

生产模式:当用户修改了有关集群的相关配置会触发生产模式,在生产模式下,服务启动会触发ES的引导检查或者叫启动检查(bootstrap checks)(或者叫启动检查),所谓引导检查就是在服务启动之前对一些重要的配置项进行检查,检查其配置值是否是合理的。引导检查包括对JVM大小、内存锁、虚拟内存、最大线程数、集群发现相关配置等相关的检查,如果某一项或者几项的配置不合理,ES会拒绝启动服务,并且在开发模式下的某些警告信息会升级成错误信息输出。引导检查十分严格,之所以宁可拒绝服务也要阻止用户启动服务是为了防止用户在对ES的基本使用不了解的前提下启动服务而导致的后期性能问题无法解决或者解决起来很麻烦。因为一旦服务以某种不合理的配置启动,时间久了之后可能会产生较大的性能问题,但此时集群已经变得难以维护,ES为了避免这种情况而做出了引导检查的设置。这种设定虽然增用户的使用门槛,但是避免了日后产生更大的问题。

7、倒排索引的基本原理

7.1基本概念 倒排索引:“关键词” ==》“ID” 即关键词到ID的映射

7.2倒排索引基本数据结构

其主要组成部分包含有:词项字典(term dictionary)、词项索引、倒排表;

词项字典是由我们的数据才分后形成的关键词,倒排表是包含关键词里面所有的id的int数组;词项索引则是该关键词项的索引;

阐述一下怎么检索的过程:

  1. 用户输入一个查询(Query),例如一个单词“Java”。
  2. 系统对查询进行与文档预处理同样的处理与分词(如转换为小写“java”)。
  3. 系统在倒排索引的词典中查找词项“java”。
  4. 如果找到,系统获取该词项对应的倒排列表(Posting List)
  5. 该倒排列表直接包含了所有包含“java”的文档ID
  6. 系统可以快速返回这些文档ID(及相关信息),或进一步:

如果数据量大的时候是怎么优化的?

FST 高效数据压缩;

在这里插入图片描述

在这里插入图片描述

核心思想:反向映射

  • 正排索引(Forward Index):从文档ID出发,映射到该文档包含的词语列表。即:文档 -> 文档内的词。这很容易构建(遍历文档分词即可),但查询时需要扫描所有文档,效率低下。
  • 倒排索引(Inverted Index):反向操作。从词语(Term)出发,映射到包含该词语的所有文档ID列表。即:词 -> 包含该词的文档列表。这通过提前建立词与文档的关系,使得基于词的查询变得极其高效。

基本原理详解:

  1. 文档预处理与分词(Tokenization and Processing):
    • 对原始文档(如网页、文章、数据库记录等)进行预处理,包括文本清理(去除HTML标签、特殊字符等)、大小写转换(通常转为小写)、分词(中文需要专门的分词器,英文通常按空格和标点切分)。
    • 结果: 每个文档被分解成一个唯一词语(Term)的集合。
  2. 构建词典(Lexicon/Dictionary):
    • 收集所有文档经过预处理和分词后得到的所有不重复的词语
    • 这些词语按照某种顺序(如字典序)排序和组织,形成词典。每个词被称为一个词项(Term)
    • 目的: 快速定位到某个词是否存在于索引中。
  3. 创建倒排列表(Posting List):
    • 对词典中的每一个词项T:
      • 遍历所有文档,找出所有包含词项T的文档ID。
      • 将所有包含T的文档ID(通常还会包含更多信息,见下文)存储在一个有序列表中。这个列表就是词项T对应的倒排列表(Posting List)
      • 关键信息通常存储在倒排列表中:
        • 文档ID(Document ID):包含该词项的文档的唯一标识符。列表按DocID排序,便于压缩和求交/并集。
        • 词频(Term Frequency, TF):该词项在此文档中出现的次数。用于相关性评分。
        • 位置信息(Position):该词项在文档中出现的位置偏移量(通常是单词序号或字符偏移)。对于短语查询或高亮显示至关重要。
        • 其他: 有时还存储权重、字段信息(如标题、正文)等。
  4. 组装倒排索引(Assembly):
    • 将每个词项T和它对应的倒排列表(包含所有相关DocID和元信息)关联起来。整个结构组成了倒排索引。
    • 可以将其视为一个 数据结构:
      • 一个键值对的集合(在Java中最自然的实现是Map<Term, PostingList>)。
      • 键(Key): 词项(Term)
      • 值(Value): 倒排列表(Posting List), 本质上是一个有序列表,每个元素记录文档ID及相关信息。

工作流程(查询时):

  1. 用户输入一个查询(Query),例如一个单词“Java”。
  2. 系统对查询进行与文档预处理同样的处理与分词(如转换为小写“java”)。
  3. 系统在倒排索引的词典中查找词项“java”。
  4. 如果找到,系统获取该词项对应的倒排列表(Posting List)
  5. 该倒排列表直接包含了所有包含“java”的文档ID
  6. 系统可以快速返回这些文档ID(及相关信息),或进一步:
    • 处理多词查询: 对于查询“Java面试”,系统需要分别查找“java”和“面试”的倒排列表,然后对两个DocID集合求交集(AND)-> 找到同时包含两者的文档。对于OR查询则求并集。
    • 排序(Ranking): 根据文档的TF、IDF(逆文档频率,衡量词的稀有程度)、位置、权重等信息计算相关性得分,对结果文档进行排序。

关键优势:

  • 高效查找: 查询速度不再依赖于文档总数,而是直接通过倒排列表定位到包含查询词的特定文档集合。时间复杂度接近O(1)(查找词项本身通常用哈希或树结构,非常高效)。
  • 支持复杂查询: 通过集合操作(交集、并集)可以高效实现AND、OR、NOT等布尔查询。
  • 支持短语查询: 利用位置信息可以查找词项在文档中按特定顺序相邻出现的记录。
  • 支持相关性排序: TF、IDF等存储在倒排列表中的信息是计算相关性的基础。

Java中的关联与应用:

  • 标准的Java集合类(如HashMap<String, List<Long>>)可以用作小型内存倒排索引的简化版演示核心思想(Key是Term,Value是包含该Term的DocID列表)。但实际系统会复杂得多。
  • Apache Lucene: Java生态中最著名、最强大的核心库,专门用于构建高性能、全功能的倒排索引。它是完全基于倒排索引的。
  • Elasticsearch & Solr: 基于Lucene构建的分布式搜索和分析引擎(Elasticsearch)和搜索服务器(Solr)。它们直接利用Lucene的倒排索引能力,并在其基础上提供分布式处理、REST API、高可用等特性。

总结来说,倒排索引就像一本书最后包含的术语索引(Index):

  • 书的正排结构: 第1章:讲述A, B, C…; 第2章:讲述B, D…
  • 书的倒排索引(索引表): A -> [页码1]; B -> [页码1, 页码2]; C -> [页码1]; D -> [页码2]

面试中回答倒排索引的基本原理,核心就是抓住 “词 -> 文档集合” 这一核心思想,强调其高效性的来源,并能简要说明构建过程和查询流程。熟悉Lucene作为Java实现的标杆能大大加分。

8、为什么ES不使用B+树做底层的数据结构

1.索引往往字段很长,如果使用B+trees,树可能很深,IO很可怕
2.性能无法保证并且索引会失效
3.精准度差(相关度低),并且无法和其他属性产生相关性

// 可以假设如果使用B+树存储:

在这里插入图片描述

讲述一下底层存储引擎的查询数据的核心:IO磁盘交互;

  1. B+加数据的存储数据结构:当数据量越大时候,由于我们这个都是以文档的形式,当存储数据文本大的时候,可能需要一个或者多个节点,从而导致树都深度增加
  2. 后续通过文本查询的时候:一般是%like%查询,会失效
  3. 并且查询的时候只有当前的查询条件,无法并列出来其他的相关度;倒排索引的相关度()

核心答案:

Elasticsearch (ES) 不使用 B+ 树作为其_核心的、主要的_底层数据结构(用于倒排索引和全文检索)是因为 B+ 树的设计目标与搜索引擎的核心需求存在关键的不匹配。B+ 树是为高效的精确查找、范围查询和事务处理优化的(典型 OLTP 场景),而搜索引擎的核心需求是 极快的全文检索、高效的词项匹配以及灵活的相关性评分

以下是具体原因和分析:

  1. 核心数据结构目的不同:

    • B+ 树: 主要服务于键值查找(精确匹配)和有序范围扫描。它在数据库中常用于组织表的主键索引或辅助索引,确保按特定键快速找到记录。
    • ES的核心 (Lucene): 使用的是 倒排索引。它的目的是 高效地根据词项(Token)查找包含该词项的所有文档(Posting List)。这是全文检索的基础。
  2. 查询效率的侧重点不同:

    • 倒排索引的优势(词项查找): 对于查询 “包含关键词 ‘apple’ 的文档有哪些?”,倒排索引的实现(词典找到词项 -> 直接获取倒排列表)比 B+ 树(需要树遍历比较键)要高效得多。尤其是在需要对多个词项进行 AND/OR 操作(合并倒排列表)时,倒排索引的效率优势更明显。
    • B+树的优势(有序范围/精确值): B+ 树在按范围查找(如 date BETWEEN ‘2023-01-01’ AND ‘2023-01-31’) 或精确键值匹配上有优势,但这种查询在全文检索场景中虽然是必要的补充,但不是核心
  3. 空间利用与压缩:

    • 倒排索引: 其倒排列表天然地可以进行各种高效压缩(如 FOR、RLE、PForDelta),因为文档 ID 通常是升序的,差值可压缩,词频、位置信息也都有规律。这对于存储海量文档的词项关联至关重要。
    • B+树: 虽然节点内数据也可以压缩,但其结构设计(中间节点的索引项)主要不是为了文档 ID 列表这种密集型、有序数字集合的最高压缩比而优化的。
  4. 处理“部分匹配”和“相关性”:

    • 倒排索引:

      天然存储了词项在每个文档中的信息:

      • 文档 ID 列表: 哪些文档包含这个词。
      • 词频: 该词在文档中出现的次数(TF)。
      • 位置信息: 该词在文档中出现的位置(用于短语查询、邻近度查询)。
      • Payloads/Norms: 存储自定义信息或长度归一化因子。
      • 这些信息是计算文档相关性(如 TF-IDF、BM25)的直接输入。词典(Term Dictionary)部分也方便实现前缀查询、通配符查询和模糊查询。
    • B+树: 主要存储键(例如文档 ID 或某个字段值)和指向记录的指针(或值本身)。它并不直接存储多个词项与文档的关系,也无法高效地存储和利用位置、词频信息来进行相关性打分。在 B+ 树上模拟倒排索引的功能非常低效。

  5. 写入优化(LSM Tree 思想):

    • 虽然 Lucene (ES) 的核心索引结构是倒排索引,但其底层存储和合并策略(Segment 模型)大量借鉴了 LSM 树的思想:写入缓冲 -> 生成不可变的 Segment 文件 -> 后台合并
    • 这种结构对写入密集型的操作(大量文档索引)更友好:
      • 高写入吞吐: 大部分写入是追加或生成新文件。
      • 避免原地更新开销: Segment 一旦生成就不可变,避免了 B+ 树频繁的节点分裂、合并和树平衡开销(尤其是在高并发写入时)。
    • B+树在写入密集场景的问题: B+ 树需要维护严格的树结构平衡,插入/更新/删除操作可能导致节点分裂、合并和树结构调整。这些操作涉及到磁盘 I/O(对于大型树,很多节点在磁盘上)和写放大问题(改写整个节点页),在高并发写入或大数据量场景下可能成为瓶颈。
  6. 分片与分布式:

    • ES 的分布式特性建立在索引被分割成多个分片的基础上。分片内部的核心数据结构是倒排索引。基于词项的分区(如按词项哈希)或基于文档的分区,在倒排索引的基础上更容易理解和实现,并支持并行检索。
    • B+ 树作为一种全局有序结构,在分布式环境下维护其全局有序性和高效查询会更加复杂。

总结:

Elasticsearch 选择倒排索引(而非 B+ 树)作为其核心数据结构,是由搜索引擎的根本任务决定的

  • 任务: 根据用户输入的一个或多个词(Token),快速找到包含这些词的所有相关文档,并按相关性排序。
  • 最佳工具: 倒排索引完美解决了 “词 -> 文档列表” 的高效映射问题,并能存储支持高级检索和相关性排名所需的额外信息(位置、词频等)。
  • B+树的局限: B+ 树擅长精确值和有序范围扫描,但它是为管理记录(行)的访问而设计的,而不是为了高效地管理词项与文档之间复杂的关系网络。它在处理全文检索的核心操作上不是最佳选择

补充说明:

  • ES 中确实部分使用了类似 B+ 树的结构Doc Values。Doc Values 是列式存储结构,用于处理聚合、排序、脚本访问等需要按文档顺序高效访问字段值的场景。它的实现确实利用了有序的、类似 B+ 树或 BKD 树的特性来实现快速的范围查询、精确值查找和排序。这恰恰印证了不同数据结构适用于不同场景:倒排索引用于“词找文档”,Doc Values 用于“文档找值(排序聚合)”。
  • 倒排索引的词典查找部分也会用到类似的数据结构(如 FST - Finite State Transducer),但这些优化的目的都是为了让词典查找更快,服务于倒排索引的核心功能。

面试回答建议:

  1. 开门见山: “ES 的核心数据结构是倒排索引,而不是 B+ 树,这是因为倒排索引是专门为解决全文检索的核心问题——快速查找包含特定词项的文档列表而设计的,而 B+ 树更擅长精确值查找和范围查询,这在传统数据库事务管理中是关键需求。”
  2. 对比优势:
    • “对于 ‘词项 -> 文档列表’ 这种操作,倒排索引的效率远高于 B+ 树,因为它相当于一个巨大的哈希表(加上对文档列表的优化),查找几乎是 O(1) 复杂度加上列表遍历。”
    • “倒排索引天然存储了词频、位置等关键信息,这些是计算相关性评分的基础,B+ 树结构难以有效存储和利用这些信息。”
    • “ES 的底层 Segment 机制(写入缓冲 + 不可变段 + 合并)借鉴了 LSM Tree 思想,极大优化了写入吞吐量,避免了 B+ 树在高并发写入时的分裂合并开销。”
    • “倒排索引的文档列表可以进行高效压缩,这对于存储海量数据至关重要。”
  3. 承认 B+ 树的用途: “当然,ES 也利用了一些树结构。比如 Doc Values 用于聚合和排序字段时,内部就可能采用类似 B+ 树或 BKD 树的结构来实现高效的列式扫描和范围查询。这表明了在不同场景下选用合适数据结构的重要性。”
  4. 总结: “因此,选择倒排索引而非 B+ 树作为 ES 的核心数据结构,是 ES 的设计目标(成为强大的全文搜索引擎)与其内在特性之间的最佳匹配。”

清晰地阐述倒排索引解决的核心问题以及它与 B+ 树的本质区别,就能很好地回答这个问题。

(请注意:现在是东八区北京时间 2025 年 7 月 21 日 22 时 43 分 34 秒,星期一。此回答基于此时间点的知识和上下文。)

这是一个经典的面试问题,关键在于理解搜索引擎和传统数据库的核心需求差异。Elasticsearch(ES)不使用B+树作为核心数据结构的原因主要基于以下核心要点:

📖 核心答案框架
  1. 核心数据结构目的不同
    • B+树:为精确值查找和范围查询优化(OLTP场景),如通过ID查记录或按范围过滤。
    • ES(底层是Lucene):使用倒排索引,核心目标是解决“词项→文档列表”的映射问题(全文检索基础)。
  2. 查询效率的侧重点差异
    • 倒排索引在词项匹配上的优势:
      • 搜索"apple"时,倒排索引通过词典(O(1)复杂度)直接获取文档ID列表,合并多个词项列表(AND/OR操作)效率极高。
      • 天然支持相关性计算(存储词频、位置信息),便于TF-IDF/BM25等算法。
    • B+树的局限:
      • 树结构遍历(O(log N))在全文检索时效率低于倒排索引。
      • 无法高效存储词频、位置等全文检索必需信息。
  3. 写入优化设计差异
    • ES的分段存储模型(Segment):
      • 写入时缓冲数据生成不可变Segment文件,后台异步合并(类似LSM树)。
      • 优势:写入吞吐高(追加操作),避免B+树频繁分裂/合并的I/O开销。
    • B+树在高并发写入时的瓶颈:
      • 需维护树平衡,节点分裂合并导致写放大和磁盘I/O竞争。
  4. 存储压缩效率
    • 倒排索引的文档ID列表(有序数字)支持高效压缩(如FOR、PForDelta),节省磁盘空间。
    • B+树压缩能力较弱,中间节点包含冗余指针信息。
  5. 分布式场景适应性
    • 倒排索引的分片策略(基于词项或文档)更契合分布式并行检索。
    • B+树维护全局有序性在分布式环境下复杂度极高。
💡 关键结论对比
特性 倒排索引(ES) B+树(传统数据库)
核心用途 全文检索、词项→文档映射 精确值/范围查询、事务处理
查询"apple"效率 O(1)词典查找 + 列表合并 O(log N)树遍历
写入吞吐量 高(缓冲+异步合并) 低(节点分裂/合并开销大)
相关性计算支持 内置(词频/位置存储) 不支持
压缩效率 极高(文档ID差值压缩) 一般
分布式适应 天然契合(分片并行检索) 复杂(需维护全局有序)
⚖️ 辩证补充(面试加分项)
  • ES中B+树的影子
    ES的doc values(用于排序/聚合)实际使用B+树或BKD树结构,说明​​在非核心场景仍需传统结构​​。
  • 数据佐证:
    • 测试显示:千万级数据中,B+树的3次I/O查询耗时约30ms,倒排索引的词典查找+列表合并可控制在10ms内。
    • 写入压测:ES索引吞吐可达每秒数万文档,B+树型数据库通常低1个数量级。

总结回答示例
“ES选择倒排索引而非B+树,本质是由其核心需求决定的:搜索引擎需要极致化的全文检索效率,而倒排索引通过词典直取文档列表的能力远超B+树的树遍历。此外,倒排索引天然支持词频/位置存储(相关性计算)、分段写入模型(高吞吐)、以及分布式友好的分片策略——这些特性与B+树擅长的精确查询/事务处理形成了正交差异。当然,ES在聚合等场景也通过Doc Values使用了类似B+树的结构,验证了’不同问题需适配不同工具’的设计哲学。”

9、ES写入原理

在这里插入图片描述

Elasticsearch (ES) 的写入过程是高效、分布式且面向搜索优化的,核心围绕着索引操作。其写入原理可以概括为以下几个关键阶段和机制:

  1. 客户端请求与路由:
    • 客户端(如应用、Logstash)向 Elasticsearch 集群发送一个 索引(Index)或 创建(Create)请求,包含要写入的文档数据、目标索引名称以及可选的文档 ID。
    • 请求通常先发送到一个协调节点
    • 协调节点根据文档的 _id值(或自动生成)和路由算法(默认为 _id的哈希值)计算该文档属于哪个主分片
    • 协调节点将请求直接转发给该主分片所在的数据节点
  2. 数据节点处理(主分片操作):
    • 接收请求的数据节点(该分片的主分片节点)执行以下核心操作:
      • a. 写入内存 Buffer 和 Translog:
        • 内存索引缓存: 文档首先被添加到 In-Memory Buffer。这是一个位于内存中的队列,主要作用是批量处理写入以提高吞吐量。
        • 事务日志: 同时,文档操作被立即且顺序地记录到 Transaction Log (Translog) 文件(每个分片有自己的 Translog)。Translog 是持久化在磁盘上的(默认每次写请求后刷盘)。这是 Crash-Safety 的关键!即使节点突然宕机,重启后也能根据 Translog 恢复未持久化的数据。
      • b. Refresh (刷新): 这不是由写入请求直接触发的,而是一个定时/阈值触发的过程(默认每秒一次,可通过 index.refresh_interval配置)。
        • 定期将 In-Memory Buffer 中的内容清空。
        • 在内存中创建一个新的、不可变Lucene Segment。这个新 Segment 包含了被清空的 Buffer 中的文档。
        • 这个新的 Segment 被打开,使其包含的文档变得可被搜索(searchable。这就是为什么 ES 有“近实时搜索”特性——文档通常在 1 秒内可见,而不需要等到完全落盘。
        • Refresh 操作相对轻量,因为它主要是内存操作(生成新 Segment),并且不保证数据持久化到物理存储(磁盘)。持久化由 Flush 负责。
      • c. Flush (刷盘): 这是一个将数据真正、安全地持久化到磁盘的过程,由以下条件触发(可配置):
        • Translog 大小达到阈值 (index.translog.flush_threshold_size):默认 512MB。
        • 定期时间间隔 (index.translog.sync_interval/ index.translog.durability):默认每 5 秒检查一次是否需要 flush,或者设置为 request则每次写后强制(牺牲性能保安全)。
        • 显式调用 Flush API。
        • Lucene Commit: 在 Flush 时,ES 会执行一次 Lucene Commit
          • 将所有在内存中 Refresh 生成但未提交的 Lucene Segments 安全地写入磁盘(.dvd, .dvm, .fdt, .fdx, .tim, .tip等文件),确保数据物理存储。
          • 创建一个新的 Commit Point,记录当前所有有效的 Segments。
          • 清空(删除或归档)当前 Translog:因为 Commit 之后的数据已经安全落地,不再需要依赖旧的 Translog 恢复这些数据。一个新的空 Translog 被创建。
        • Flush 确保了持久性(Durability),但开销比 Refresh 大很多,因为涉及磁盘 I/O。
  3. 副本分片同步 (Replication):
    • 在主分片节点成功处理写入(完成第 2 步 a:写入 Translog)后:
      • 它将并行地将该写入操作转发给该分片的所有副本分片所在的节点。
      • 副本分片节点执行与主分片完全相同的操作序列(写入内存 Buffer & Translog,等待后续的 Refresh 和 Flush)。
    • 只有等到配置要求数量的副本分片都确认写入成功(默认是 wait_for_active_shards,如 all, quorum, 或具体数字),主分片节点才会向协调节点报告写入成功。这确保了写入的一致性级别
    • 重要: 副本分片的写入是异步进行的(尽管请求流是并行的),协调节点和主节点等待的是副本分片_确认操作已被接收并加入其本地 Translog_,而不是必须完成 Refresh 或 Flush。
  4. 返回响应:
    • 主分片节点收到足够的副本分片确认(Translog 写入成功)后,通知协调节点。
    • 协调节点最终将 Created(HTTP 201) 或带有版本号的响应返回给客户端。
  5. 后台操作 (Segment Merge):
    • Lucene 在后台会运行一个进程将小的 Segments 合并成更大的 Segments
    • 合并过程:
      • 删除被标记为删除的文档(旧版本或在 delete操作)。
      • 优化存储结构(减少碎片化)。
      • 降低最终所需的文件句柄数量。
      • 提升查询效率(查一个大文件可能比查很多小文件快)。
    • 合并是 I/O 和 CPU 密集型操作,ES 有策略(如 TieredMergePolicy)自动管理这个过程。

总结关键点与设计目标:

  • 近实时搜索 (NRT):Refresh 机制实现,默认每秒将内存中的文档变为可搜索,平衡了搜索延迟和写入性能。
  • 持久性保证 (Durability):TranslogFlush 机制共同保证:
    • Translog: 记录每一次写操作,保证即使在内存数据丢失时也能恢复未持久化的数据。写入的立即持久化首先发生在 Translog 上。
    • Flush: 将内存中累积的数据(Segments)安全持久化到磁盘,并截断 Translog。
  • 高性能写入:
    • 内存 Buffer: 批量处理。
    • 异步 Replication: 不等待副本完全持久化才返回(只等它们接收了写入操作)。
    • 延迟刷盘: Refresh(轻量,内存)与 Flush(重量,磁盘 I/O)分离,减少频繁磁盘访问。
  • 分布式一致性: 通过主分片协调写入,并在主分片与配置数量的副本分片之间确认 Translog 写入完成,保证写入操作的所需一致性级别(通过 wait_for_active_shards控制)。
  • 面向搜索优化: Segments 是只读的(不可变),有利于并发搜索;后台合并优化存储和查询性能。

简单记忆流程(单次写入):

客户端请求 -> 
协调节点路由 -> 
主分片节点写入 (内存 Buffer + 立即写 Translog) -> 
主分片节点并发转发写请求到副本分片 -> 
副本分片也写入 (Buffer + Translog) -> 
主分片等待足够副本确认 -> 返回成功 -> 
后续:定时 Refresh(近实时搜索) + 条件触发 Flush(持久化) + 后台 Segment Merge(优化)

理解 ES 的写入原理对于配置集群参数、调优性能、保证数据安全以及诊断问题至关重要。

10、写入优化

  • 尽量使用buk批量写入
  • 增加flush时间间隔,目的是减小数据写入磁盘的频率,减小磁盘1O
  • 增加refresh_interval的参数值,目的是减少segment文件的创建,减少segment的nerge次数,merge是发生在ivm中的,有可能导
    致full GC,增加refresh会降低搜索的实时性。
  • 增加Buffer大小,本质也是减小refresh的时间间隔,因为导致segment文件创建的原因不仅有时间阈值,还有ouffer空间大小,写满
    了也会创建。
  • 默认最小值48MB<默认值堆空间的10%<默认最大无限制
  • 大批量的数据写入尽量控制在低检索请求的时间段,大批量的写入请求越集中越好。
    • 第一是减小读写之间的资源抢占,读写分离
    • 第二,当检索请求数量很少的时候,可以减少甚至完全删除副本分片,关闭segment的自动创建以达到高效利用内存的目的,因
      为副本的存在会导致主从之间频繁的进行数据同步,大大增加服务器的资源占用。
  • Lucene的数据的fsync是发生在OS cachel的,要给OS cache预留足够的内从大小,详见VM调优。
  • 通用最小化算法,能用更小的字段类型就用更小的,keyword类型比int更快
  • ignore_above:字段保留的长度,越小越好
  • 调整source?字段,通过include和exclude过滤

Elasticsearch 写入优化是一个系统工程,需要在理解其写入原理的基础上,针对特定的硬件、数据模式和业务需求进行多方面的调整。以下是一些关键的优化策略和方向:

📍 一、 降低写入操作的频率与开销

  1. 📤 使用 Bulk API:
    • 这是最重要的优化!将所有单条写入 (index) 请求 合并 成批量请求 (bulk) 再发送给 ES。
    • 优势: 显著减少网络开销、每个请求的处理开销(解析、路由)、磁盘 I/O(特别是 Translog 刷盘,如果配置了 "durability": "request")。
    • 大小建议: 找到最佳平衡点 (通常在 5-15 MB)。太小效果不明显,太大可能导致内存压力、GC 或请求超时。监控节点指标(堆内存、GC、IO)来调整。
  2. ⏳ 调大 Refresh Interval (index.refresh_interval):
    • 默认值 1s: 使数据可搜索的延迟很低(近实时),但对写入性能有显著影响,因为每秒都会在内存中创建新 segment。
    • 优化: 将刷新间隔调大(例如 30s60s-1在批量导入期间暂时关闭)。这大大减少了在内存中创建 Lucene segment(成本相对较高)的频率。
    • 副作用: 数据可见/可搜索的延迟增加。需要根据业务对搜索实时性的要求调整。导入完成后可调整回较小值。
  3. 🧾 优化 Translog 行为:
    • index.translog.durability:
      • request(默认): 每次写请求 (index, delete, bulk) 后立即将 Translog 刷新落盘。数据安全最高,性能开销最大(频繁刷盘)。
      • async: 在后台异步刷新 Translog(默认间隔 5s, 由 index.translog.sync_interval控制)。极显著提升写入性能。数据丢失风险:丢失最近 sync_interval时间段内(如 5s)的已确认写入。适用于可以容忍此级别风险的场景(如日志、指标)。
    • index.translog.flush_threshold_size:
      • 默认 512MB。控制触发一次 flush操作的阈值。增大此值(如 1GB)意味着更少地执行昂贵的 flush操作(将内存中的 segment 真正持久化到磁盘并清除旧的 translog),更多依赖后台的 refresh 和 translog。
      • 风险: 更大的阈值意味着单个 flush 操作耗时更长(涉及更多数据写入磁盘)& 节点故障时恢复时间更长(需重放更大 Translog)。

📍 二、 优化数据结构与索引配置

  1. 🚫 禁用不必要的特性:
    • _source:
      • 禁用 ("enabled": false) 可以节省磁盘空间和减少写入时的处理开销(不需要存储原始 JSON)。
      • 巨大代价: 无法执行 update, reindex, highlighting, 部分聚合,以及无法查看原始文档。一般强烈不推荐禁用。
    • _all/ copy_to(若使用): ES 6.0 后 _all废弃。如果使用 copy_to创建类似功能,评估其必要性,不需要则避免。
    • 字段映射中的 index属性: 对于不用于搜索或聚合的字段(例如仅用于存储或返回结果的元数据字段),设置为 "index": false。避免不必要的索引和分析过程。考虑使用 Pass-through attributes
    • Norms: 对于不分词仅做精确值过滤 (keyword) 或不需要相关性评分的字段,设置 "norms": false节省内存和磁盘。
    • doc_values: 对于绝对不需要聚合或排序的字段,可以禁用 ("doc_values": false)。谨慎使用,多数情况需要打开。
  2. 📉 减少字段数量:
    • 避免过度嵌套 (Nested Object)。
    • 避免过多字段(大几百上千)。这增加了每个文档的内存占用、Lucene 内部结构复杂度、mapping 管理开销。
    • 考虑使用 Flattened类型处理键值对或不需要单独索引的复杂对象,或使用 Pass-through attributes存储。
    • 精心设计数据模型和索引映射。
  3. ⏱️ 优化时间序列数据 (Index per Timeframe):
    • 对于日志、指标等按时间递增写入的数据,不要写入一个无限增大的索引。应使用索引生命周期管理 (ILM) 或 Rollover API 按时间周期(如每天、每周)创建新索引。
    • 优势:
      • 新索引写入更快(fresh segment)。
      • 旧索引可优化(只读、force merge、降低副本数)、冻结或删除。
      • 更高效的冷热数据分离架构(如利用 SSD 存热数据,HDD 存温数据)。

📍 三、 集群架构与硬件优化

  1. ⚖️ 增加写入节点:
    • 设置专门的协调/仅写入节点 (node.roles: [ ingest, ml ])。在较大集群中,避免让数据节点承担大量协调工作(解析请求、聚合结果)。
    • 拆分集群角色 (Master, Data, Ingest, ML, Coordinating) 实现资源隔离和专业化扩容。
    • 将写入请求均匀分发到协调节点池(负载均衡)。
  2. 🔁 调整副本数量 (index.number_of_replicas):
    • 默认 1(每个主分片 1 个副本)。临时降低副本数(在批量导入期间设置为 0 可以显著提高写入吞吐量,因为写入不需要等待副本同步。
    • 注意:
      • 降低副本数会影响可用性和查询性能。
      • 导入完成后必须将副本数恢复,否则数据安全性降低 (主分片丢失后数据不可恢复)。
    • 不能简单认为提高副本数会提升写入速度。更多副本意味着更多的数据同步开销(主->多个副本)。核心目标是通过临时降低同步压力来提写入。
  3. 💾 使用高性能硬件:
    • CPU: Lucene 和 ES 索引过程是 CPU 密集型(尤其分析)。更强、更多的核心有助于并行处理。
    • 磁盘 I/O: SSD!这是最重要的硬件投资。SATA/SAS SSD 是底线,NVMe SSD 是高性能首选。确保足够大的 IOPS 和带宽。
    • 内存:
      • 足够大的堆内存 (通常不超过 31GB, 通常设置为物理内存的 50% 但不超 31GB) 给 JVM,避免频繁 GC (建议 CMS 或 G1GC)。
      • 足够大的操作系统文件系统缓存 (Filesystem Cache)。剩余物理内存给 OS Cache,用于缓存 segment 文件,加速搜索和后续写入时的文件访问。避免堆过大导致没有足够 OS Cache。
      • 确保 indices.memory.index_buffer_size(默认为堆的 10%) 足够,避免因 Buffer 满而频繁 Refresh。监控节点 stats 中的索引缓冲区使用情况。
    • 网络: 保证数据节点之间、协调节点与客户端之间的网络带宽充足且稳定(避免丢包),低延迟。

📍 四、 优化段合并 (Segment Merging)

  1. ⚙️ 调整 Merge Policy: (高级, 谨慎操作)
    • Lucene 的 TieredMergePolicy是合理的默认值。
    • 可以尝试增大 index.merge.policy.segments_per_tier(默认 10),减少每层级的 segment 数量,从而减少 merge 频率(但每次 merge 可能更大)。调整 index.merge.scheduler.max_thread_count(默认根据核心数自动计算,通常为 Math.min(4, Math.max(1, (availableProcessors + 1) / 2 ))) 控制并发 merge 线程数,避免过多并发 merge 耗尽 I/O。
    • 重点: 在完成大型数据导入后,针对旧索引进行 Force Merge(如 POST my-index/_forcemerge?max_num_segments=1&only_expunge_deletes=false)。这大大减少 segment 数量,提升后续查询性能、减少文件句柄占用、释放磁盘空间。注意:Force Merge 是极其资源密集型操作,只能在只读索引的维护窗口进行!

📍 五、 其他优化点与监控

  1. 📇 Monitor Document ID Quality:
    • 使用随机性较强的 _id(如 UUID v4)。单调递增的 ID (如时间序列 ID timestamp-xxx) 可能导致 Lucene 连续插入新文档到同一 segment,影响 merge 效率。ES 能处理,但随机 ID 通常是更好的选择。
    • 如果使用 ES 自动生成 ID (POST my-index/_doc, 不带 id),它是随机的,没有问题。
  2. 📊 监控, 监控, 再监控!
    • 使用 Kibana Stack Monitoring 或 Prometheus+Grafana (配合 ES Exporter) 密切监控关键指标:
      • 索引速率 (indexing_index_total/ indexing_index_time): 观察时间平均值是否达到瓶颈。
      • 线程池 (thread_pool.write.queue, thread_pool.write.rejected): 队列积压或被拒绝是明显的瓶颈信号。
      • GC (jvm.gc.collectors.young.count/duration, old): 频繁且耗时的 GC 严重影响性能。
      • IO (fs.io_stats.io_time, iostat, diskstats): 磁盘是否成为瓶颈?IO等待是否高?
      • CPU (os.cpu.percent): 单核是否打满?
      • Segment Count/Size (indices.segments.count, indices.segments.memory): segment 是否过大或过多?
      • Index Buffer Usage (indices.memory.index_buffer_percent): 是否经常达到 Buffer 容量上限?
    • Profiling: 使用 Hot Threads API(GET /_nodes/hot_threads) 排查性能瓶颈点。
📌 优化总结与实践建议
  1. 📐 基准测试与基线: 优化前测量当前性能(索引速率、延迟、资源使用)作为基线。
  2. 🔍 优先级排序:
    • 必做: Bulk API, 合理设计索引周期(Time-based)。
    • 强力优化点: 调大 refresh_interval(尤其批量导入时), 调整 translog.durability=async(如可接受风险)。
    • 资源配置: 投入 SSD, 平衡好 JVM HeapOS Cache的大小, 配置合理内存 Buffer。
    • 负载均衡: 部署 专用协调节点
    • 分批导入: 在导入期间 临时降低副本数=0, 导入完恢复。
  3. 📄 理解配置: 仔细阅读官方文档中每个配置项的含义和默认值。elasticsearch.yml和索引级设置 (PUT index/_settings) 都重要。
  4. 📊 持续监控: 优化是一个持续迭代过程,任何改动都要观察监控指标变化。
  5. ⚖️ 权衡的艺术: 所有优化都有 trade-off。务必根据业务对数据安全性搜索实时性成本性能的要求来选择策略。例如,为了极致写入速度 (async translog+ refresh_interval -1+ 0 replicas),需要接受潜在的少量数据丢失、搜索延迟增加、以及恢复期更高风险。

通过综合运用以上策略,通常可以显著提升 Elasticsearch 的写入吞吐量并降低延迟,以满足不断增长的数据摄入需求。💪🏻

11、ES类型

  • master:候选节点
  • data:数据节点
  • data content:数据内容节点
  • data hot:热节点
  • data warm:索引不再定期更新,但仍可查询
  • data code:冷节点,只读索引
  • Ingest:预处理节点,作用类似于Logstash中的Filter
  • ml:机器学习节点
  • remote cluster_client:候选客户端节点
  • transform:转换节点
  • voting_only:仅投票节点

12、ES读写调优

Elasticsearch 的读写调优需要综合考虑数据写入效率和查询性能,这两者常常存在一定程度的权衡(Trade-off)。以下是一个全面的优化策略框架,结合核心原理、参数调整、集群架构和实战经验:


📌 一、写入优化(回顾与增强)

目标:提升吞吐量(doc/s),降低写入延迟,减轻集群负载。

  1. 核心策略

    • 强制使用 Bulk API:合并小请求(5-15MB/批次),避免单条写入。

    • ⏱️ 增大 Refresh Intervalindex.refresh_interval: "30s"(默认1s),降低 Lucene Segment 生成频率。

    • 异步 Translog(风险可控时):

      PUT /my_index/_settings
      {
        "index.translog.durability": "async",
        "index.translog.sync_interval": "5s"
      }
      
      
    • 🔧 优化内存分配

      # elasticsearch.yml
      indices.memory.index_buffer_size: 20%   # 默认10%,增大可减少刷新
      
      
  2. 场景化技巧

    • 数据批量导入:临时设置 number_of_replicas: 0+ refresh_interval: -1,完成后还原。

    • 时间序列数据:使用 ILM 按时间滚动索引(如每日索引),新索引写入更快。

    • 禁用非必要特性

      "index": false,   // 不搜索的字段
      "doc_values": false // 不排序/聚合的字段
      
      

🔍 二、读优化(查询加速)

目标:降低查询延迟,提高并发能力,避免慢查询。

  1. 缓存优化

    • 查询缓存(Query Cache):自动缓存高频过滤查询,确保 size参数合理(避免缓存大结果集)。
    • 文件系统缓存(OS Cache):预留 ≥50% 物理内存给 OS Cache(非堆内存),加速磁盘文件读取。
    • 分片请求缓存(Shard Request Cache):对聚合类查询效果显著,通过 ?request_cache=true启用。
  2. 查询优化技巧

    • Filter 替代 Query:用 filter上下文(不计算相关性)处理过滤条件,结果可缓存。
    • 🔢 避免深度分页:用 search_after代替 from+size(超过 1000 页性能骤降)。
    • ⚠️ 拒绝 Wildcard 查询*开头通配符导致全索引扫描,改用分词或 Ngram。
    • 🔍 合理使用聚合
      • 避免多层嵌套聚合。
      • 对高基数字段(如 user_id)用 cardinality时调整 precision_threshold
  3. 索引设计优化

    • 🧩 Force Merge 只读索引:减少 Segment 数量提升查询性能(执行后需锁定索引)。

      POST /old_index/_forcemerge?max_num_segments=1
      
      
    • ❄️ 冻结历史索引:对极少访问的数据使用 Frozen Index,通过顺序读取优化冷数据查询。


⚖️ 三、读写平衡的关键设置
参数 写入优化值 读优化值 说明
refresh_interval 30s 或 -1 1s 写入期调大,查询期调小
number_of_replicas 0(临时) ≥1 写入时降副本,完成恢复
index.translog.durability async request 异步提交写入更快但风险略高
index.merge.scheduler.max_thread_count 2 4 机械硬盘降低并发,SSD可提高

🖥️ 四、集群架构优化
  1. 角色分离(大规模集群):

    • 协调节点(Coordinating Only):仅处理路由和结果聚合,配置 node.roles: [ ]

    • 热冷数据分离

      node.attr.temperature: hot   # SSD 节点
      node.attr.temperature: warm  # HDD 节点
      
      

      通过 ILM 自动迁移数据。

  2. 硬件与资源分配

    • SSD 磁盘:必选(NVMe > SATA SSD),避免机械硬盘。
    • JVM 堆内存:≤ 30GB(避免超过 32GB 指针压缩阈值),堆外内存留给 OS Cache。
    • 线程池监控:关注 writesearch队列,拒绝请求时需扩容或优化逻辑。

🛠️ 五、监控与诊断工具
  1. 关键指标

    • 写入indexing ratemerge timetranslog ops
    • 查询search latencyquery_cache evictionsfetch time
    • 资源:CPU、IO Wait、Heap Used、GC Count。
  2. 诊断命令

    GET _nodes/hot_threads           # 热点线程分析
    GET /_cat/thread_pool?v          # 线程池状态
    GET /_stats/merges?human         # 段合并开销
    
    

💎 调优总结
  1. 写入优先:批量提交 → 降低刷新 → 异步日志 → 临时降副本。
  2. 查询加速:缓存优化 → 避免深分页 → Filter 优先 → 冻结冷数据。
  3. 动态平衡:根据业务场景灵活调整 refresh_intervalreplicas等参数。
  4. 根治慢查询:通过 Profile API 定位慢查询根源(如 "profile": true参数)。

⚠️ 注意事项

  • 每次修改参数后持续监控集群状态(建议在预发环境验证)。
  • 避免过度优化(如将所有缓存设为最大),资源是有限的。
  • 版本升级可能影响性能(如 ES 8.x 默认关闭 _all)。

通过以上策略的组合应用,可使 ES 集群在高吞吐写入场景下仍保持稳定的查询响应能力。实际调优需结合业务数据模式(如日志/电商/监控)进行针对性测试。
.attr.temperature: warm # HDD 节点
```

 通过 ILM 自动迁移数据。

  1. 硬件与资源分配

    • SSD 磁盘:必选(NVMe > SATA SSD),避免机械硬盘。
    • JVM 堆内存:≤ 30GB(避免超过 32GB 指针压缩阈值),堆外内存留给 OS Cache。
    • 线程池监控:关注 writesearch队列,拒绝请求时需扩容或优化逻辑。

🛠️ 五、监控与诊断工具
  1. 关键指标

    • 写入indexing ratemerge timetranslog ops
    • 查询search latencyquery_cache evictionsfetch time
    • 资源:CPU、IO Wait、Heap Used、GC Count。
  2. 诊断命令

    GET _nodes/hot_threads           # 热点线程分析
    GET /_cat/thread_pool?v          # 线程池状态
    GET /_stats/merges?human         # 段合并开销
    
    

💎 调优总结
  1. 写入优先:批量提交 → 降低刷新 → 异步日志 → 临时降副本。
  2. 查询加速:缓存优化 → 避免深分页 → Filter 优先 → 冻结冷数据。
  3. 动态平衡:根据业务场景灵活调整 refresh_intervalreplicas等参数。
  4. 根治慢查询:通过 Profile API 定位慢查询根源(如 "profile": true参数)。

⚠️ 注意事项

  • 每次修改参数后持续监控集群状态(建议在预发环境验证)。
  • 避免过度优化(如将所有缓存设为最大),资源是有限的。
  • 版本升级可能影响性能(如 ES 8.x 默认关闭 _all)。

通过以上策略的组合应用,可使 ES 集群在高吞吐写入场景下仍保持稳定的查询响应能力。实际调优需结合业务数据模式(如日志/电商/监控)进行针对性测试。

Java开发的就业市场正在经历结构性调整,竞争日益激烈

传统纯业务开发岗位(如仅完成增删改查业务的后端工程师)的需求,特别是入门级岗位,正显著萎缩。随着企业技术需求升级,市场对Java人才的要求已从通用技能转向了更深入的领域经验(如云原生、微服务)或前沿的AI集成能力。这也导致岗位竞争加剧,在一、二线城市,求职者不仅面临技术内卷,还需应对学历与项目经验的高门槛。

大模型为核心的AI领域正展现出前所未有的就业热度与人才红利

2025年,AI相关新发岗位数量同比激增543%,单月增幅最高超过11倍,大模型算法工程师位居热门岗位前列。行业顶尖人才的供需严重失衡,议价能力极强,跳槽薪资涨幅可达30%-50%。值得注意的是,市场并非单纯青睐算法研究员,而是急需能将大模型能力落地于复杂业务系统的工程人才。这使得具备企业级架构思维和复杂系统整合经验的Java工程师,在向“Java+大模型”复合人才转型时拥有独特优势,成为企业竞相争夺的对象,其薪资天花板也远高于传统Java岗位。

在这里插入图片描述

说真的,这两年看着身边一个个搞Java、C++、前端、数据、架构的开始卷大模型,挺唏嘘的。大家最开始都是写接口、搞Spring Boot、连数据库、配Redis,稳稳当当过日子。

结果GPT、DeepSeek火了之后,整条线上的人都开始有点慌了,大家都在想:“我是不是要学大模型,不然这饭碗还能保多久?”

先给出最直接的答案:一定要把现有的技术和大模型结合起来,而不是抛弃你们现有技术!掌握AI能力的Java工程师比纯Java岗要吃香的多。

即使现在裁员、降薪、团队解散的比比皆是……但后续的趋势一定是AI应用落地!大模型方向才是实现职业升级、提升薪资待遇的绝佳机遇!

如何学习AGI大模型?

作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

2025最新版CSDN大礼包:《AGI大模型学习资源包》免费分享**

一、2025最新大模型学习路线

一个明确的学习路线可以帮助新人了解从哪里开始,按照什么顺序学习,以及需要掌握哪些知识点。大模型领域涉及的知识点非常广泛,没有明确的学习路线可能会导致新人感到迷茫,不知道应该专注于哪些内容。

我们把学习路线分成L1到L4四个阶段,一步步带你从入门到进阶,从理论到实战。

L1级别:AI大模型时代的华丽登场

L1阶段:我们会去了解大模型的基础知识,以及大模型在各个行业的应用和分析;学习理解大模型的核心原理,关键技术,以及大模型应用场景;通过理论原理结合多个项目实战,从提示工程基础到提示工程进阶,掌握Prompt提示工程。

L2级别:AI大模型RAG应用开发工程

L2阶段是我们的AI大模型RAG应用开发工程,我们会去学习RAG检索增强生成:包括Naive RAG、Advanced-RAG以及RAG性能评估,还有GraphRAG在内的多个RAG热门项目的分析。

L3级别:大模型Agent应用架构进阶实践

L3阶段:大模型Agent应用架构进阶实现,我们会去学习LangChain、 LIamaIndex框架,也会学习到AutoGPT、 MetaGPT等多Agent系统,打造我们自己的Agent智能体;同时还可以学习到包括Coze、Dify在内的可视化工具的使用。

L4级别:大模型微调与私有化部署

L4阶段:大模型的微调和私有化部署,我们会更加深入的探讨Transformer架构,学习大模型的微调技术,利用DeepSpeed、Lamam Factory等工具快速进行模型微调;并通过Ollama、vLLM等推理部署框架,实现模型的快速部署。

整个大模型学习路线L1主要是对大模型的理论基础、生态以及提示词他的一个学习掌握;而L3 L4更多的是通过项目实战来掌握大模型的应用开发,针对以上大模型的学习路线我们也整理了对应的学习视频教程,和配套的学习资料。

二、大模型经典PDF书籍

书籍和学习文档资料是学习大模型过程中必不可少的,我们精选了一系列深入探讨大模型技术的书籍和学习文档,它们由领域内的顶尖专家撰写,内容全面、深入、详尽,为你学习大模型提供坚实的理论基础(书籍含电子版PDF)

三、大模型视频教程

对于很多自学或者没有基础的同学来说,书籍这些纯文字类的学习教材会觉得比较晦涩难以理解,因此,我们提供了丰富的大模型视频教程,以动态、形象的方式展示技术概念,帮助你更快、更轻松地掌握核心知识

四、大模型项目实战

学以致用 ,当你的理论知识积累到一定程度,就需要通过项目实战,在实际操作中检验和巩固你所学到的知识,同时为你找工作和职业发展打下坚实的基础。

五、大模型面试题

面试不仅是技术的较量,更需要充分的准备。

在你已经掌握了大模型技术之后,就需要开始准备面试,我们将提供精心整理的大模型面试题库,涵盖当前面试中可能遇到的各种技术问题,让你在面试中游刃有余。


因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

2025最新版CSDN大礼包:《AGI大模型学习资源包》免费分享

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐