深入浅出Elasticsearch:功能、特性及核心实现

深入浅出系列

深入浅出Elasticsearch:功能、特性及核心实现

在大数据时代,我们每天都会产生海量数据——日志、文本、用户行为、商品信息等等,如何快速从这些数据中检索、分析有价值的信息,成为企业和开发者的核心需求。而Elasticsearch(简称ES),正是这样一款能搞定“海量数据实时检索与分析”的开源神器。

很多人初识ES,只知道它是“搜索引擎”,但其实它的能力远不止于此。今天我们就来好好聊聊:ES到底有哪些实用功能和独特特性?而这些强大的能力,又依赖于哪些核心架构和算法来支撑?全程干货,兼顾入门理解与技术深度,适合开发者、运维同学,也适合想了解ES核心逻辑的小伙伴。

一、Elasticsearch 核心功能与核心特性

在聊底层支撑之前,我们先明确ES能做什么、有什么过人之处——毕竟,架构和算法都是为“功能落地”服务的,先懂应用,再看原理,会更易理解。

(一)核心功能:不止是“搜索”,更是“数据处理中枢”

ES的核心功能围绕“数据的写入、检索、分析、管道处理、高可用扩展及生态集成”展开,覆盖从基础查询到复杂分析的全场景,结合最新版本特性,日常开发中最常用的有以下5大类:

1. 数据存储与检索

作为ES的基础功能,核心是实现数据的高效存储与快速检索,适配多场景数据需求:

A. 分布式文档存储:以JSON文档为核心存储单元,支持Schema-free动态映射,无需提前定义表结构,大幅降低数据接入门槛;同时支持静态映射,生产环境可预定义字段类型,保障性能与稳定性。

B. 近实时搜索 (NRT):数据写入后,默认1秒内就能被检索到,既能满足“实时更新”的需求(如电商商品库存实时检索),又能保证检索性能,完美兼顾写入吞吐与检索时效性。

C. 全文检索:这是ES最基础也最核心的功能,支持中文、英文等多语言检索,搭载中文IK分词器等多语言分词工具,核心能力涵盖分词处理、相关性排序、模糊匹配(支持通配符、正则表达式、Fuzzy查询、拼写纠错)、短语匹配、高亮显示、自动补全(Completion Suggester)、同义词扩展(语义扩展搜索),同时支持搜索模板,可预定义查询逻辑,整体响应速度可达毫秒级。

D. 结构化查询:支持精确匹配(term)、范围查询(range)、布尔逻辑查询、地理坐标(geo)等多种检索方式,可处理多类型数据——结构化数据以JSON文档形式存储,非结构化文本通过全文检索处理,地理空间数据支持位置搜索与范围查询,数值数据支持范围查询与统计计算,适用于日志分析、订单查询等各类场景。

E. 多租户:通过索引级别隔离实现多租户数据分离,避免数据混淆,适配多租户、高并发的业务需求,同时支持跨集群搜索(CCS),可统一查询多集群数据。

2. 数据分析

ES区别于普通搜索引擎的核心优势,提供多维度、高效的数据分析能力,覆盖时序、地理、机器学习等场景:

A. 聚合分析 (Aggregation):提供强大的多维实时统计分析与数据挖掘能力,包括指标聚合(如avg平均值、sum求和)、分桶聚合(如terms分组、date_histogram时间分桶)及管道聚合,支持多层级流水线计算,无需额外数据处理工具,就能实现实时业务洞察。

B. 时序数据分析:专门针对日志、指标等时序数据设计,支持时序索引(按天/周生成索引)、时间序列分析,可高效处理时序数据的检索与聚合,适配日志分析、系统监控等场景。

C. 地理空间分析:支持Geo-point、Geo-shape类型的地理空间数据存储与查询,可实现距离计算、范围查询、多边形查询等地理空间分析能力,适用于地图定位、区域筛选等场景。

D. 机器学习 (X-Pack):作为ES的扩展能力,支持异常检测、预测、分类等机器学习功能,可自动捕捉系统异常(如错误率突增),实现风险预测与智能分析,适配安全风控、系统监控等场景。

E. 向量搜索 (8.x+):ES 8.x及以上版本原生支持语义相似度检索,通过Dense Vector类型存储向量数据,搭配Flat、HNSW索引结构,实现高效的kNN搜索,同时支持混合搜索,通过RRF(Reciprocal Rank Fusion)算法组合查询结果,适配AI场景、语义检索等需求。

3. 数据管道

负责数据写入前、查询时的预处理与增强,减少业务层处理压力,提升数据质量:

A. Ingest Pipeline:即摄取节点的核心功能,在数据写入之前,对原始数据进行过滤、转换、enrichment(如添加时间戳、解析JSON、字段清洗),将原始数据处理成符合业务需求的格式,再写入数据节点。

B. 数据转换 (Transform):可将聚合分析的结果持久化为新的索引,方便后续快速查询与复用,减少重复聚合计算的成本。

C. 数据丰富 (Enrich):在查询时关联外部数据(如关联用户画像、字典数据),丰富查询结果,提升数据的完整性与实用性。

4. 高可用与扩展

保障ES集群稳定运行,支持海量数据与高并发场景的扩展需求:

A. 水平扩展:天生支持分布式部署,可动态添加节点,实现存储与计算能力的线性扩展,轻松承载TB级、PB级数据处理需求。

B. 数据冗余:通过自动副本分片机制实现数据冗余,副本数量可动态调整,既保障数据安全,又能分担读请求压力。

C. 故障转移:支持自动主节点选举、分片重定位,当主节点或数据节点故障时,副本可无缝接管,集群自动完成故障恢复,避免数据丢失与服务中断。

D. 跨集群复制 (CCR):实现异地多活、读写分离,可将主集群的数据实时复制到从集群,提升服务可用性与读取性能,适配异地部署场景。

E. 跨集群搜索 (CCS):可统一查询多个ES集群的数据,打破集群边界,实现多集群数据的集中检索与分析。

5. 生态集成

ES并非孤立运行,拥有完善的生态系统,可与多种工具、服务集成,覆盖数据采集、可视化、大数据处理等全流程:

A. Elastic Stack:与Beats(轻量级数据采集工具)、Logstash(数据管道处理)、Kibana(数据可视化与分析)深度集成,构成ELK生态,覆盖数据采集→处理→存储→检索→可视化全流程。

B. 多语言客户端:提供Java、Go、Python、JS等多种主流编程语言客户端,兼容不同技术栈,降低开发成本。

C. 云服务集成:支持与AWS S3、Azure、GCP等主流云服务集成,可将数据备份到云存储,实现弹性扩展。

D. 大数据集成:可与Hadoop、Spark、Flink等大数据框架集成,实现海量数据的分布式处理与检索,适配大数据场景。

(二)核心特点:为什么大家都选ES?四大维度关键优势

除了强大的功能,ES的特性更是让它成为“首选工具”,这些特性也正是其底层架构和算法要重点支撑的目标,主要分为四大维度:

1. 分布式特性

A. 自动分片:数据写入时自动水平切分,无需人工干预,将数据分布到不同的分片,实现分布式存储与并行处理。

B. 自动均衡:通过Allocation模块,实现分片的自动分配与迁移,当节点新增或故障时,自动调整分片分布,确保集群负载均衡。

C. 无单点故障:部署多个主节点候选,通过选举机制产生主节点,避免主节点单点故障,保障集群稳定运行。

D. 横向线性扩展:性能随节点数量线性提升,新增节点即可扩展存储与计算能力,无需重构集群架构。

2. 搜索特性

A. 相关性排序:默认基于BM25概率模型计算相关性得分,也支持TF/IDF算法,可通过boost调整字段权重,确保返回最贴合用户需求的结果。

B. 多字段搜索:支持跨多个字段联合搜索,可灵活调整不同字段的权重,适配复杂搜索场景(如电商商品多维度搜索)。

C. 模糊匹配:支持Fuzzy查询、拼写纠错(基于Levenshtein距离算法),即使输入关键词存在拼写错误,也能返回相关结果。

D. 高亮显示:搜索结果中自动高亮匹配的关键词,提升用户体验,适用于网站搜索、日志检索等场景。

E. 自动补全:通过Completion Suggester实现搜索关键词自动补全,提升搜索效率,适配搜索框自动提示场景。

F. 搜索模板:可预定义查询逻辑,封装复杂的DSL查询语句,减少重复开发,提升查询一致性。

3. 性能特性

A. 内存缓存:内置多层缓存机制,包括Filter Cache(过滤器结果缓存)、Fielddata Cache(字段缓存)、请求缓存,减少重复查询的计算成本,提升查询速度。

B. 零拷贝:采用MMap文件映射技术,减少数据在内存与磁盘之间的拷贝,提升I/O性能。

C. 列式存储:默认启用Doc Values列式存储,将字段值按列存储,优化排序与聚合操作的性能,解决传统行存储在聚合场景下的性能瓶颈。

D. 索引压缩:采用FOR(Frame of Reference)、RBM(Roaring Bitmap)等压缩算法,对倒排索引、文档ID列表进行压缩,大幅减少内存占用与磁盘存储开销。

E. 并行处理:支持分片级并行查询,多个分片同时执行查询操作,再由协调节点聚合结果,缩短查询响应时间。

4. 运维特性

A. 动态映射:自动识别JSON字段类型,无需提前定义表结构,降低数据接入门槛,生产环境建议预定义映射以保障性能。

B. 索引生命周期:通过ILM(索引生命周期管理)功能,实现数据热-温-冷-冻的自动迁移与管理,优化存储成本,减少人工运维。

C. 快照备份:支持增量快照备份,可将备份数据存储到本地或远程存储(如AWS S3),确保数据安全,便于灾难恢复。

D. 监控告警:内置监控API,可实时监控集群状态、节点性能、索引健康度,结合Kibana可视化展示,同时支持内置告警系统,异常时触发多渠道通知(如邮件、短信)。

E. 安全认证:ES 8.x及以上版本默认开启Security模块,支持RBAC权限模型、JWT/OAuth2身份认证、TLS传输加密、TDE存储加密(AES-256加密),同时具备审计日志功能,记录敏感操作,保障集群与数据安全。

二、深度拆解:支撑ES特性的核心架构

ES的所有功能和特性,都依赖于其“分布式集群架构”——它不是单一服务,而是由多个节点组成的集群,每个节点承担不同的角色,协同工作,既保证了扩展性,又保证了高可用。我们从“集群整体结构”“数据模型”“核心流程”“关键机制”四个维度,拆解其核心架构,并明确功能→架构→算法的映射关系。

(一)集群与节点:分布式的“骨架”

ES集群由多个“节点(Node)”组成,每个节点都是一个独立的ES进程,节点之间通过内部通信机制协同工作,共同构成一个完整的集群(即集群架构,多节点协同工作)。集群有一个唯一的名称,节点通过这个名称加入集群,自动发现其他节点——ES 7+版本基于Raft-like共识机制(替代旧版Zen Discovery)实现节点自动加入与主节点选举,同时采用Bully选举算法辅助主节点选举,均能有效防止脑裂(需部署奇数个主节点候选);同时采用一致性哈希算法,支撑分片分配与路由,确保数据分配均衡。

节点按功能可分为4类,各司其职、角色分离,有效避免资源竞争,支撑整个集群的高效运行:

A. 主节点(Master-eligible Node):集群的“管理者”,负责集群元数据管理(如索引创建、分片分配)、节点加入/退出、选主等操作,不负责数据的写入和查询,确保集群管理的轻量高效。为了高可用,集群通常会部署多个主节点候选,避免单点故障。

B. 数据节点(Data Node):集群的“数据载体”,负责数据的存储、索引构建、查询、聚合等核心操作,是ES集群中最核心的工作节点。数据量越大,需要的data节点越多,可通过横向增加data节点实现扩容。

C. 协调节点(Coordinating Node):集群的“请求中转站”,负责接收客户端的请求,将请求路由到对应的data节点,再将所有data节点的返回结果聚合、排序后,返回给客户端。协调节点不存储数据,只负责请求的分发和结果的汇总,减轻data节点的压力。

D. 摄取节点(Ingest Node):集群的“数据预处理员”,负责执行Ingest Pipeline,在数据写入之前,对数据进行过滤、转换、enrichment,将原始数据处理成符合业务需求的格式,再写入data节点,减少业务层的预处理成本。

(二)数据模型:数据如何在ES中存储?

ES的数据存储模型,是实现“高效检索”的基础,核心是“索引-分片-文档-映射”的层级结构:

A. 索引(Index):相当于关系型数据库的“数据库”,是一个逻辑上的集合,用于存储具有相似结构的数据(如“用户日志索引”“商品信息索引”)。每个索引有唯一的名称,操作数据时需指定对应的索引;同时支持索引生命周期管理(ILM),实现热-温-冷-冻数据的自动迁移。

B. 分片与副本机制:ES采用分片机制实现数据水平分割存储,副本机制实现数据冗余与高可用,两者结合支撑分布式存储与检索。主分片实现数据水平切分,负责数据写入与修改;副本分片提供数据冗余与读负载均衡,副本数量可动态调整,进一步提升集群可用性与查询性能;同时通过最终一致性策略,实现数据副本同步,确保主副分片数据一致;底层依赖哈希路由(routing)算法实现分片分配,通过主从复制机制实现副本同步,通过故障检测算法实现故障转移。

C. 文档(Document):ES中最小的数据单元,相当于关系型数据库的“行”,以JSON格式存储(如一条用户日志、一个商品信息)。每个文档有一个唯一的ID(可自定义或自动生成),用于唯一标识文档;同时支持Version版本控制,采用乐观锁(CAS机制)实现并发控制,避免数据写入冲突。

D. 映射(Mapping):相当于关系型数据库的“表结构”,用于定义文档中每个字段的类型(如text、keyword、date、number、Geo-point、Geo-shape、Dense Vector)、分词规则、是否可检索等。ES支持动态映射(自动识别字段类型)和静态映射(手动定义字段类型),合理的映射设计是提升检索性能的关键——生产环境建议预定义映射,避免动态映射带来的性能隐患。

E. 索引结构细节:ES底层依赖Lucene索引结构,核心包括两部分:
Inverted Index(倒排索引):核心用于全文检索,由Term Dictionary(FST压缩)、Postings List(DocID+TF+Pos+Offset)、Term Index(前缀树索引)组成,通过FST(有限状态转换器)压缩词典,采用FOR、RBM算法压缩Postings List,提升检索速度并减少内存占用。

Doc Values(列存):核心用于聚合、排序操作,将原始值通过Ordinals编码后压缩存储,搭配跳过列表加速访问,大幅优化聚合性能。

(三)核心流程:写入与查询的“底层逻辑”

ES的“近实时”“高可靠”特性,本质上是由其写入和查询流程决定的,各环节对应的架构与算法:

1. 写入流程(保证高可靠、近实时)

数据写入的核心目标是“不丢数据、快速可检索”,完整流程如下:

A. 客户端发送写入请求到协调节点;

B. 协调节点通过路由算法(shard = hash(_routing) % primary_shard_count),将请求路由到该数据对应的主分片所在的data节点;

C. 数据先经过Ingest Pipeline预处理(如过滤、转换),再由主分片节点将数据写入“内存缓冲区”,同时写入“translog”(事务日志)——translog是ES的“数据安全保障”,类似数据库的redo log,负责记录所有写操作日志,采用顺序写、fsync策略确保数据持久化,即使节点宕机,重启后可通过translog恢复未落盘的数据;

D. 主分片写入完成后,将数据同步到对应的副本分片,副本分片写入完成后,向主分片返回确认;

E. 每隔1秒(默认),ES执行一次“refresh”操作,将内存缓冲区中的数据写入“segment”( Lucene的索引片段),此时数据可被检索(这就是“近实时”的核心:1秒可检索);

F. 当translog达到一定大小或间隔一定时间,ES执行“flush”操作,将segment落盘,同时清空translog,完成数据的持久化。

关键说明:写入流程的近实时性由Refresh机制支撑,数据持久化由Translog事务日志支撑,Segment管理由Lucene段文件架构支撑,采用TieredMergePolicy合并策略优化Segment性能。

2. 查询流程(保证高效、准确)

查询流程的核心目标是“快速聚合结果、返回精准匹配”,完整流程如下:

A. 客户端发送查询请求到协调节点;

B. 协调节点解析查询请求,通过查询规划器优化查询执行计划,再将查询请求广播到所有相关的主分片和副本分片(可通过配置选择优先查询副本,分担压力);

C. 每个分片在本地执行查询,进行分词、匹配、打分(基于BM25/TF-IDF算法)、排序,执行Query Phase,返回Top N结果(文档ID+相关性得分)给协调节点;

D. 协调节点对所有分片返回的Top N结果进行全局排序、聚合,执行Fetch Phase,从对应分片获取完整文档;

E. 协调节点将最终结果返回给客户端。

关键说明:查询流程的高效性由分布式查询架构、多层缓存(Filter Cache、Fielddata Cache)、并行处理机制支撑,相关性由BM25/TF-IDF算法支撑,多条件查询由跳表(Skip List)算法加速倒排列表交集计算。

(四)索引生命周期管理(ILM):冷热数据的“智能管家”

为了优化存储成本、提升集群性能,ES提供索引生命周期管理(ILM)功能,核心是实现冷热数据分离,通过自动化策略减少人工干预:

A. 冷热数据分离:将数据分为热、温、冷、冻四个阶段,热节点采用SSD存储新数据,适配高并发写入与高频检索;温节点采用HDD存储旧数据,兼顾存储成本与查询需求;冷数据进一步降低存储成本,冻数据可归档,数据会根据生命周期策略自动在不同节点间迁移。

B. 自动化策略:可自定义索引的热、温、冷、冻、删除阶段规则(如按数据年龄、索引大小),ES会自动执行索引迁移、收缩、删除等操作,无需人工手动管理,大幅降低运维成本。

此外,ES还具备完善的查询处理架构,包含查询规划器(优化查询执行计划)、分布式查询(跨分片查询聚合)、多层缓存(查询缓存、字段缓存、请求缓存)及流水线处理(查询结果聚合处理),进一步提升查询效率;同时支持跨集群复制(CCR)架构,基于序列号的增量复制算法,实现异地多活与读写分离。

三、关键支撑:让ES高效运行的核心算法

如果说架构是ES的“骨架”,那么算法就是ES的“灵魂”——正是这些核心算法,支撑了ES的全文检索、相关性排序、高效查询等能力。结合大纲“功能→架构→算法”映射关系,重点讲解所有核心算法/机制,避开复杂公式,聚焦核心逻辑和作用。

(一)分布式存储与高可用相关算法

支撑ES分布式特性、高可用特性的核心算法,确保数据均衡分布、故障自动恢复:

A. 哈希路由(routing)算法:核心公式为shard = hash(routing) % primary_shard_count,默认routing为文档ID,也支持自定义路由键(如用户ID),核心作用是将文档均匀分配到不同的主分片,避免数据倾斜,底层依赖一致性哈希算法实现分片分配与请求路由的高效性。

B. 主从复制与故障检测算法:支撑副本机制与故障转移,主分片将数据同步到副本分片,采用最终一致性策略确保数据一致;通过故障检测算法实时监控节点状态,当主节点或数据节点故障时,自动触发故障转移,将副本分片升级为主分片。

C. 选举算法:包括Bully选举算法、Raft-like共识机制,用于主节点选举,确保集群有唯一的主节点,防止脑裂,保障集群稳定运行。

D. 权重均衡算法与感知调度:由Allocation模块支撑,根据节点负载、硬件配置、数据分布情况,自动调整分片分配,实现集群负载均衡,提升集群整体性能。

E. 基于序列号的增量复制算法:支撑跨集群复制(CCR),通过记录数据写入的序列号,实现主集群到从集群的增量数据复制,确保异地集群数据一致,实现异地多活。

(二)近实时搜索相关算法/机制

支撑ES近实时特性、数据持久化的核心算法/机制:

A. Refresh机制:默认每1秒执行一次,将内存缓冲区中的数据写入Segment(不刷盘),实现数据1秒内可检索,是近实时搜索的核心机制。

B. Translog事务日志机制:采用顺序写、fsync策略,记录所有写操作,确保数据持久化,即使节点宕机,重启后可通过Translog恢复未落盘的数据,是数据安全的核心保障。

C. TieredMergePolicy合并策略:支撑Segment合并,ES自动将多个小Segment合并成一个大Segment,减少Segment数量,提升查询效率,同时去除重复数据、优化索引结构。

D. Version版本控制与乐观锁(CAS机制):实现并发控制,避免数据写入冲突,每个文档有唯一版本号,写入时校验版本,确保数据一致性。

(三)全文检索与相关性相关算法

支撑ES全文检索、相关性排序的核心算法,是ES“搜索能力”的核心支撑:

A. 倒排索引算法:ES能实现快速全文检索的核心,将“文档→词”的正排索引转为“词→文档”的倒排索引,通过Term Dictionary(词字典)和Term Index(词索引)分层存储,结合FST(有限状态转换器)压缩词典,实现词的快速定位,即使索引中存在百万级、千万级的词,也能瞬间找到对应的文档列表。

B. Postings List压缩算法:采用FOR(Frame of Reference)、RBM(Roaring Bitmap)算法,对文档ID列表进行压缩,大幅减少内存占用,同时不影响查询性能。

C. 相关性评分算法:

BM25算法:ES 5+版本默认评分模型,优化了TF-IDF的词频饱和问题,核心逻辑是根据词频(TF)、逆文档频率(IDF)、文档长度归一化计算相关性得分,计算公式为:score = Σ (IDF × (f × (k1 + 1)) / (f + k1 × (1 – b + b × (|d| / avgdl)))),其中k1控制词频饱和度,b控制文档长度归一化。

TF-IDF算法:早期评分模型,仍可按需启用,核心逻辑是通过词频(TF)和逆文档频率(IDF)衡量词的重要性,计算文档与查询词的相关性。

D. 分词算法:支撑多语言检索,由Analysis模块实现,核心包括有限状态机分词、IK字典树分词(中文),常用分词器有standard(英文)、IK(中文,分粗粒度ik_smart和细粒度ik_max_word)、whitespace(按空格拆分)等,同时支持自定义停用词、同义词。

E. 同义词/拼写纠错算法:由Token Filter链支撑,同义词通过同义词词典匹配实现,拼写纠错基于Levenshtein距离算法,计算输入关键词与词典中词的相似度,实现拼写错误修正。

F. 跳表(Skip List)算法:加速倒排列表的交集计算(如多条件查询),将时间复杂度从O(n)降至O(log n),大幅提升多条件查询效率。

(四)聚合分析相关算法

支撑ES聚合分析能力的核心算法,确保聚合操作高效、精准:

A. 列式压缩与Ordinals映射:支撑Doc Values列存,将原始值通过Ordinals编码后压缩存储,搭配跳过列表加速访问,大幅优化聚合、排序性能。

B. HyperLogLog++算法:用于基数统计(Cardinality聚合),在保证误差率<0.5%的前提下,大幅降低内存占用,适用于海量数据的去重统计。

C. TDigest算法:用于百分位计算(Percentiles聚合),平衡计算精度与性能,适用于海量数据的百分位统计(如95分位响应时间)。

D. Map-Reduce两阶段聚合算法:支撑分布式聚合引擎,第一阶段(Map)由各分片本地执行聚合,第二阶段(Reduce)由协调节点汇总各分片结果,实现海量数据的高效聚合。

E. 多层级流水线计算:支撑Bucket/Metric/Pipeline嵌套聚合,通过多阶段流水线处理,实现复杂的多层级聚合分析,挖掘数据深层规律。

(五)地理空间相关算法

支撑ES地理空间分析功能的核心算法,适配地理空间查询与聚合需求:

A. BKD树索引(Block KD-tree):用于Geo-point/Geo-shape类型数据的存储与索引,高效支持地理坐标的快速检索,是地理空间查询的核心索引结构。

B. 距离计算算法:包括Haversine公式、SloppyMath,用于计算两个地理坐标之间的距离,支撑地理距离查询。

C. GeoHash、H3网格索引:用于地理范围查询,将地理空间划分为网格,快速定位指定范围内的地理数据,提升范围查询效率。

D. R-Tree索引、射线法:用于多边形查询,通过R-Tree索引优化多边形数据存储,采用射线法判断点是否在多边形内,实现精准的多边形地理查询。

(六)向量搜索相关算法(8.x+)

支撑ES 8.x及以上版本向量搜索功能的核心算法,适配AI场景、语义检索需求:

A. Flat、HNSW索引结构:用于Dense Vector类型向量数据的存储,Flat索引适用于小规模向量,查询精准;HNSW(Hierarchical Navigable Small World)索引适用于大规模向量,兼顾查询速度与精度,是向量搜索的核心索引结构。

B. HNSW算法:用于kNN搜索API,通过构建分层导航小世界图,实现高效的近似最近邻搜索,大幅提升大规模向量的检索速度。

C. RRF(Reciprocal Rank Fusion)算法:用于混合搜索,将向量搜索与传统全文搜索的结果进行融合排序,提升搜索结果的相关性与完整性。

(七)安全与权限相关算法/机制

支撑ES安全特性的核心算法/机制,保障集群与数据安全:

A. RBAC模型、JWT/OAuth2:支撑身份认证,RBAC(基于角色的访问控制)模型用于权限管理,JWT/OAuth2用于身份验证,确保只有授权用户才能访问集群资源。

B. SSL/TLS 1.3:用于TLS层传输加密,保障数据在节点之间、客户端与集群之间的传输安全,防止数据泄露。

C. AES-256加密:用于TDE(透明数据加密)模块,对存储在磁盘上的数据进行加密,保障数据静态安全。

D. 事件驱动记录机制:支撑审计日志功能,记录集群的敏感操作(如用户登录、索引删除),便于安全审计与问题追溯。

四、版本演进与架构变化

ES的版本迭代过程中,核心架构与功能不断优化,重点版本变化,如下表所示(清晰呈现版本、关键架构变化及影响):

版本 关键架构变化 影响
2.x → 5.x 移除Fielddata默认、引入BKD树 减少OOM(内存溢出),提升数值、地理空间数据的查询性能
6.x 单Type限制、稀疏字段优化 为7.x完全移除Type做准备,优化稀疏字段的存储与查询性能
7.x 新集群协调层、Voting配置 脑裂防护更完善,集群启动速度更快,提升集群稳定性
8.x Security默认开启、向量搜索原生支持、Java API重构 开箱即用更安全,AI场景(语义检索)支持增强,开发体验提升

五、典型场景与架构匹配

ES的强大之处,在于其架构与算法可根据不同业务场景灵活适配,以下是3个最典型的场景及对应的架构配置:

A. 日志分析场景:采用冷热架构(热节点处理新日志,温节点存储历史日志)+ ILM生命周期策略,搭配批量写入优化(调大refresh_interval),结合Logstash/Beats数据采集、Kibana可视化,使用时序索引与聚合分析,适配海量日志的集中管理与分析,同时利用Translog保障数据安全,通过Segment合并优化查询性能。

B. 电商搜索场景:搭载IK分词器(实现中文商品名精准分词)+ BM25评分算法(优化热销商品排序,提升用户搜索体验)+ 过滤聚合(支持品牌、价格区间等多维度筛选),结合DSL查询语言、同义词扩展、自动补全功能,使用分片与副本机制保障高可用,利用缓存机制提升查询速度,完美适配电商平台的商品搜索与筛选需求。

C. 监控告警场景:采用时序索引(按天/周生成索引,便于管理)+ pipeline聚合(计算指标变化率,捕捉系统异常)+ watcher告警(设置阈值,异常时触发通知),搭配Kibana Dashboard监控,利用机器学习(X-Pack)实现异常检测,结合跨集群复制(CCR)实现异地多活,降低运维成本,保障监控服务稳定。

D. 语义检索(AI场景):基于ES 8.x向量搜索功能,使用Dense Vector类型存储向量数据,配置HNSW索引,结合RRF算法实现混合搜索(向量搜索+全文搜索),搭配数据丰富(Enrich)功能关联外部数据,实现语义相似度检索,适配AI问答、智能推荐等场景。

六、总结与实用小贴士

看到这里,相信你已经搞懂了ES的核心逻辑:ES的强大,源于“分布式架构”提供的扩展性和高可用,以及“倒排索引、BM25、分词”等核心算法提供的高效检索能力——架构是“基础保障”,算法是“效率核心”,再加上完善的性能优化机制、生态系统集成与版本迭代优化,让ES成为海量数据检索与分析的首选工具。

最后给大家3个实用小贴士,帮你在实际使用中避坑:

A. 索引设计时,提前规划主分片数量:主分片一旦创建不可修改,建议根据数据量、扩容计划合理设置(比如初期数据量小,设置3-5个主分片,后续通过水平增加data节点扩容);同时合理配置副本数,兼顾高可用与性能;可结合ILM策略与存储优化机制(如压缩算法),降低长期存储成本。

B. 合理选择字段类型:text类型用于全文检索,keyword类型用于精准查询、排序、聚合,Geo-point/Geo-shape用于地理空间数据,Dense Vector用于向量数据,避免将text类型用于排序和聚合(会导致性能低下、结果不准确);生产环境建议预定义映射,避免动态映射带来的隐患;同时合理配置缓存策略,提升查询性能。

C. 版本选择与运维优化:根据业务需求选择合适的ES版本,8.x版本推荐用于需要向量搜索、高安全需求的场景;运维时重点监控集群状态、内存使用、Segment合并情况,避免GC卡顿,定期进行快照备份,确保数据安全;针对高并发场景,可优化Refresh间隔、批量写入大小,提升集群性能。

如果觉得这篇文章对你有帮助,欢迎点赞、收藏,也可以在评论区留言,聊聊你在使用ES时遇到的问题~

ElasticSearch2基本操作(06关于查询条件及过滤)

过滤

match_all 全部匹配,不做过滤,默认
term 精确匹配
terms 精确匹配多个词
range 范围匹配
exists 文档包含某属性
missing 文档不包含某属性
bool 多个过滤条件的组合

其中,对于bool过滤,可以有下面的组合条件:

must 多个查询条件的完全匹配,相当于 and。
must_not 多个查询条件的相反匹配,相当于 not。
should 至少有一个查询条件匹配, 相当于 or。

查询

match_all 全部匹配,默认
match 首先对查询条件进行分词,然后用TF/IDF评分
multi_match 与match类似,但可以用多个条件
bool 多个条件的组合查询

其中,对于bool查询,可以有下面的组合条件:

must 多个查询条件的完全匹配,相当于 and。
must_not 多个查询条件的相反匹配,相当于 not。
should 至少有一个查询条件匹配, 相当于 or。
#查询性别为男,年龄不是25,家庭住址最好有魔都两个字的记录
curl -XPOST http://127.0.0.1:9200/myindex/user/_search -d'
{
    "query": {
        "bool": {
            "must": {
                "term": {
                    "性别": "男"
                }
            },
            "must_not": {
                "match": {
                    "年龄": "25"
                }
            },
            "should": {
                "match": {
                    "家庭住址": "魔都"
                }
            }
        }
    }
}'

#查询注册时间从2015-04-01到2016-04-01的用户
curl -XPOST http://127.0.0.1:9200/myindex/user/_search -d'
{
    "query": {
        "bool": {
            "must": {
                "range": {
                    "注册时间": {
                        "gte": "2015-04-01 00:00:00",
                        "lt": "2016-04-01 00:00:00"
                    }
                }
            }
        }
    }
}'

#查询没有年龄字段的记录
curl -XPOST http://127.0.0.1:9200/myindex/user/_search -d'
{
    "query": {
        "bool": {
            "must": {
                "missing": {
                    "field": "年龄"
                }
            }
        }
    }
}'

#查询家庭地址或工作地址中包含北京的用户
curl -XPOST http://127.0.0.1:9200/myindex/user/_search -d'
{
    "query": {
        "multi_match": {
            "query": "北京",
            "type": "most_fields",
            "fields": [
                "家庭住址",
                "工作地址"
            ]
        }
    }
}'

#查询性别为男的用户
curl -XPOST http://127.0.0.1:9200/myindex/user/_search -d'
{
    "query": {
        "filtered": {
            "query": {
                "match_all": {}
            },
            "filter": {
                "term": {
                    "性别": "男"
                }
            }
        }
    }
}'

#查询注册时间为两年内的用户
curl -XPOST http://127.0.0.1:9200/myindex/user/_search -d'
{
    "query": {
        "filtered": {
            "query": {
                "match_all": {}
            },
            "filter": {
                "range": {
                    "注册时间": {"gt" : "now-2y"}
                }
            }
        }
    }
}'

排序

#查询所有用户,按注册时间进行排序
curl -XPOST http://127.0.0.1:9200/myindex/user/_search -d'
{
    "query": {
        "match_all": {}
    },
    "sort": {
        "注册时间": {
            "order": "desc"
        }
    }
}'

分页

#查询前三条记录
curl -XPOST http://127.0.0.1:9200/myindex/user/_search -d'
{
    "query": {
        "match_all": {}
    },
    "from": 0,
    "size": 3
}'

带缓存的分页

#进行分页
curl -XPOST http://127.0.0.1:9200/myindex/user/_search?search_type=scan&scroll=5m -d'
{
    "query": { "match_all": {}},
    "size":  10
}'

#返回_scroll_id
{"_scroll_id":"c2Nhbjs1OzE1MzE6NVR2MmE1WWFRRHFtelVGYlRwNGlhdzsxNTMzOjVUdjJhNVlhUURxbXpVRmJUcDRpYXc7MTUzNDo1VHYyYTVZYVFEcW16VUZiVHA0aWF3OzE1MzU6NVR2MmE1WWFRRHFtelVGYlRwNGlhdzsxNTMyOjVUdjJhNVlhUURxbXpVRmJUcDRpYXc7MTt0b3RhbF9oaXRzOjc7","took":2,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":7,"max_score":0.0,"hits":[]}}

#发送_scroll_id开始查询
curl -XPOST http://127.0.0.1:9200/_search/scroll?scroll=5m
c2Nhbjs1OzE1MzE6NVR2MmE1WWFRRHFtelVGYlRwNGlhdzsxNTMzOjVUdjJhNVlhUURxbXpVRmJUcDRpYXc7MTUzNDo1VHYyYTVZYVFEcW16VUZiVHA0aWF3OzE1MzU6NVR2MmE1WWFRRHFtelVGYlRwNGlhdzsxNTMyOjVUdjJhNVlhUURxbXpVRmJUcDRpYXc7MTt0b3RhbF9oaXRzOjc7

ElasticSearch2基本操作(05关于搜索)

ES的搜索,不是关系数据库中的LIKE,而是通过搜索条件及文档之间的相关性来进行的。

对于一次搜索,对于每一个文档,都有一个浮点数字段_score 来表示文档与搜索主题的相关性, _score 的评分越高,相关性越高。

评分的计算方式取决于不同的查询类型:
fuzzy查询会计算与关键词的拼写相似程度
terms查询会计算找到的内容与关键词组成部分匹配的百分比
而全文本搜索是指计算内容与关键词的类似程度。

ES通过计算TF/IDF(即检索词频率/反向文档频率, Term Frequency/Inverse Document Frequency)作为相关性指标,具体与下面三个指标相关:
检索词频率TF: 对于一条记录,检索词在查询字段中出现的频率越高,相关性也越高。比如,一共有5个检索词,有4个出现在第一条记录,3条出现在第二条记录,则第一条记录TF会比第二条高一些。

反向文档频率IDF: 每个检索词在所有文档的该字段中出现的频率越高,则该词相关性越低。比如有5个检索词,如果一个词在所有文档中都出现,而另一个词之出现了一次,则所有文档中都包含的词几乎可以被忽略,只出现了一次的这个词权重会很高。

字段长度: 对于一条记录,查询字段的长度越长,相关性越低。比如有一条记录长度为10个词,另一条记录长度为100个词,而一个关键词,在两条记录里都出现了一次。则长度为10个词的记录,比长度为100个词的记录,相关性会高很多。

通过对TF/IDF的了解,可以让你解释一些看似不应该出现的结果。同时,你应该清楚,这不是一种精确匹配算法,而是一种评分算法,根据相关性进行了排序。

如果认为评分结果不合理,可以用下面的语句,查看评分过程:

#解释查询是如何进行评分的
crul -XPost http://127.0.0.1:9200/myindex/user/_search?explain -d'
{
   "query"   : { "match" : { "家庭住址" : "魔都大街" }}
}'

#结果如下:
{
    "took": 7,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "failed": 0
    },
    "hits": {
        "total": 4,
        "max_score": 4,
        "hits": [
            {
                "_shard": 4,
                "_node": "5Tv2a5YaQDqmzUFbTp4iaw",
                "_index": "myindex",
                "_type": "user",
                "_id": "u002",
                "_score": 4,
                "_source": {
                    "用户ID": "u002",
                    "姓名": "李四",
                    "性别": "男",
                    "年龄": "25",
                    "家庭住址": "上海市闸北区魔都大街007号",
                    "注册时间": "2015-02-01 08:30:00"
                },
                "_explanation": {
                    "value": 4,
                    "description": "sum of:",
                    "details": [
                        {
                            "value": 4,
                            "description": "sum of:",
                            "details": [
                                {
                                    "value": 1,
                                    "description": "weight(家庭住址:魔 in 0) [PerFieldSimilarity], result of:",
                                    "details": [
                                        {
                                            "value": 1,
                                            "description": "score(doc=0,freq=1.0), product of:",
                                            "details": [
                                                {
                                                    "value": 0.5,
                                                    "description": "queryWeight, product of:",
                                                    "details": [
                                                        {
                                                            "value": 1,
                                                            "description": "idf(docFreq=1, maxDocs=2)",
                                                            "details": []
                                                        },
                                                        {
                                                            "value": 0.5,
                                                            "description": "queryNorm",
                                                            "details": []
                                                        }
                                                    ]
                                                },
                                                {
                                                    "value": 2,
                                                    "description": "fieldWeight in 0, product of:",
                                                    "details": [
                                                        {
                                                            "value": 1,
                                                            "description": "tf(freq=1.0), with freq of:",
                                                            "details": [
                                                                {
                                                                    "value": 1,
                                                                    "description": "termFreq=1.0",
                                                                    "details": []
                                                                }
                                                            ]
                                                        },
                                                        {
                                                            "value": 1,
                                                            "description": "idf(docFreq=1, maxDocs=2)",
                                                            "details": []
                                                        },
                                                        {
                                                            "value": 2,
                                                            "description": "fieldNorm(doc=0)",
                                                            "details": []
                                                        }
                                                    ]
                                                }
                                            ]
                                        }
                                    ]
                                },
                                {
                                    "value": 1,
                                    "description": "weight(家庭住址:都 in 0) [PerFieldSimilarity], result of:",
                                    "details": [
                                        {
                                            "value": 1,
                                            "description": "score(doc=0,freq=1.0), product of:",
                                            "details": [
                                                {
                                                    "value": 0.5,
                                                    "description": "queryWeight, product of:",
                                                    "details": [
                                                        {
                                                            "value": 1,
                                                            "description": "idf(docFreq=1, maxDocs=2)",
                                                            "details": []
                                                        },
                                                        {
                                                            "value": 0.5,
                                                            "description": "queryNorm",
                                                            "details": []
                                                        }
                                                    ]
                                                },
                                                {
                                                    "value": 2,
                                                    "description": "fieldWeight in 0, product of:",
                                                    "details": [
                                                        {
                                                            "value": 1,
                                                            "description": "tf(freq=1.0), with freq of:",
                                                            "details": [
                                                                {
                                                                    "value": 1,
                                                                    "description": "termFreq=1.0",
                                                                    "details": []
                                                                }
                                                            ]
                                                        },
                                                        {
                                                            "value": 1,
                                                            "description": "idf(docFreq=1, maxDocs=2)",
                                                            "details": []
                                                        },
                                                        {
                                                            "value": 2,
                                                            "description": "fieldNorm(doc=0)",
                                                            "details": []
                                                        }
                                                    ]
                                                }
                                            ]
                                        }
                                    ]
                                },
                                {
                                    "value": 1,
                                    "description": "weight(家庭住址:大街 in 0) [PerFieldSimilarity], result of:",
                                    "details": [
                                        {
                                            "value": 1,
                                            "description": "score(doc=0,freq=1.0), product of:",
                                            "details": [
                                                {
                                                    "value": 0.5,
                                                    "description": "queryWeight, product of:",
                                                    "details": [
                                                        {
                                                            "value": 1,
                                                            "description": "idf(docFreq=1, maxDocs=2)",
                                                            "details": []
                                                        },
                                                        {
                                                            "value": 0.5,
                                                            "description": "queryNorm",
                                                            "details": []
                                                        }
                                                    ]
                                                },
                                                {
                                                    "value": 2,
                                                    "description": "fieldWeight in 0, product of:",
                                                    "details": [
                                                        {
                                                            "value": 1,
                                                            "description": "tf(freq=1.0), with freq of:",
                                                            "details": [
                                                                {
                                                                    "value": 1,
                                                                    "description": "termFreq=1.0",
                                                                    "details": []
                                                                }
                                                            ]
                                                        },
                                                        {
                                                            "value": 1,
                                                            "description": "idf(docFreq=1, maxDocs=2)",
                                                            "details": []
                                                        },
                                                        {
                                                            "value": 2,
                                                            "description": "fieldNorm(doc=0)",
                                                            "details": []
                                                        }
                                                    ]
                                                }
                                            ]
                                        }
                                    ]
                                },
                                {
                                    "value": 1,
                                    "description": "weight(家庭住址:街 in 0) [PerFieldSimilarity], result of:",
                                    "details": [
                                        {
                                            "value": 1,
                                            "description": "score(doc=0,freq=1.0), product of:",
                                            "details": [
                                                {
                                                    "value": 0.5,
                                                    "description": "queryWeight, product of:",
                                                    "details": [
                                                        {
                                                            "value": 1,
                                                            "description": "idf(docFreq=1, maxDocs=2)",
                                                            "details": []
                                                        },
                                                        {
                                                            "value": 0.5,
                                                            "description": "queryNorm",
                                                            "details": []
                                                        }
                                                    ]
                                                },
                                                {
                                                    "value": 2,
                                                    "description": "fieldWeight in 0, product of:",
                                                    "details": [
                                                        {
                                                            "value": 1,
                                                            "description": "tf(freq=1.0), with freq of:",
                                                            "details": [
                                                                {
                                                                    "value": 1,
                                                                    "description": "termFreq=1.0",
                                                                    "details": []
                                                                }
                                                            ]
                                                        },
                                                        {
                                                            "value": 1,
                                                            "description": "idf(docFreq=1, maxDocs=2)",
                                                            "details": []
                                                        },
                                                        {
                                                            "value": 2,
                                                            "description": "fieldNorm(doc=0)",
                                                            "details": []
                                                        }
                                                    ]
                                                }
                                            ]
                                        }
                                    ]
                                }
                            ]
                        },
                        {
                            "value": 0,
                            "description": "match on required clause, product of:",
                            "details": [
                                {
                                    "value": 0,
                                    "description": "# clause",
                                    "details": []
                                },
                                {
                                    "value": 0.5,
                                    "description": "_type:user, product of:",
                                    "details": [
                                        {
                                            "value": 1,
                                            "description": "boost",
                                            "details": []
                                        },
                                        {
                                            "value": 0.5,
                                            "description": "queryNorm",
                                            "details": []
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            },
            {
                "_shard": 0,
                "_node": "5Tv2a5YaQDqmzUFbTp4iaw",
                "_index": "myindex",
                "_type": "user",
                "_id": "u003",
                "_score": 0.71918744,
                "_source": {
                    "用户ID": "u003",
                    "姓名": "王五",
                    "性别": "男",
                    "年龄": "26",
                    "家庭住址": "广州市花都区花城大街010号",
                    "注册时间": "2015-03-01 08:30:00"
                },
                "_explanation": {
                    "value": 0.71918744,
                    "description": "sum of:",
                    "details": [
                        {
                            "value": 0.71918744,
                            "description": "product of:",
                            "details": [
                                {
                                    "value": 1.4383749,
                                    "description": "sum of:",
                                    "details": [
                                        {
                                            "value": 0.71918744,
                                            "description": "weight(家庭住址:大街 in 0) [PerFieldSimilarity], result of:",
                                            "details": [
                                                {
                                                    "value": 0.71918744,
                                                    "description": "score(doc=0,freq=1.0), product of:",
                                                    "details": [
                                                        {
                                                            "value": 0.35959372,
                                                            "description": "queryWeight, product of:",
                                                            "details": [
                                                                {
                                                                    "value": 1,
                                                                    "description": "idf(docFreq=1, maxDocs=2)",
                                                                    "details": []
                                                                },
                                                                {
                                                                    "value": 0.35959372,
                                                                    "description": "queryNorm",
                                                                    "details": []
                                                                }
                                                            ]
                                                        },
                                                        {
                                                            "value": 2,
                                                            "description": "fieldWeight in 0, product of:",
                                                            "details": [
                                                                {
                                                                    "value": 1,
                                                                    "description": "tf(freq=1.0), with freq of:",
                                                                    "details": [
                                                                        {
                                                                            "value": 1,
                                                                            "description": "termFreq=1.0",
                                                                            "details": []
                                                                        }
                                                                    ]
                                                                },
                                                                {
                                                                    "value": 1,
                                                                    "description": "idf(docFreq=1, maxDocs=2)",
                                                                    "details": []
                                                                },
                                                                {
                                                                    "value": 2,
                                                                    "description": "fieldNorm(doc=0)",
                                                                    "details": []
                                                                }
                                                            ]
                                                        }
                                                    ]
                                                }
                                            ]
                                        },
                                        {
                                            "value": 0.71918744,
                                            "description": "weight(家庭住址:街 in 0) [PerFieldSimilarity], result of:",
                                            "details": [
                                                {
                                                    "value": 0.71918744,
                                                    "description": "score(doc=0,freq=1.0), product of:",
                                                    "details": [
                                                        {
                                                            "value": 0.35959372,
                                                            "description": "queryWeight, product of:",
                                                            "details": [
                                                                {
                                                                    "value": 1,
                                                                    "description": "idf(docFreq=1, maxDocs=2)",
                                                                    "details": []
                                                                },
                                                                {
                                                                    "value": 0.35959372,
                                                                    "description": "queryNorm",
                                                                    "details": []
                                                                }
                                                            ]
                                                        },
                                                        {
                                                            "value": 2,
                                                            "description": "fieldWeight in 0, product of:",
                                                            "details": [
                                                                {
                                                                    "value": 1,
                                                                    "description": "tf(freq=1.0), with freq of:",
                                                                    "details": [
                                                                        {
                                                                            "value": 1,
                                                                            "description": "termFreq=1.0",
                                                                            "details": []
                                                                        }
                                                                    ]
                                                                },
                                                                {
                                                                    "value": 1,
                                                                    "description": "idf(docFreq=1, maxDocs=2)",
                                                                    "details": []
                                                                },
                                                                {
                                                                    "value": 2,
                                                                    "description": "fieldNorm(doc=0)",
                                                                    "details": []
                                                                }
                                                            ]
                                                        }
                                                    ]
                                                }
                                            ]
                                        }
                                    ]
                                },
                                {
                                    "value": 0.5,
                                    "description": "coord(2/4)",
                                    "details": []
                                }
                            ]
                        },
                        {
                            "value": 0,
                            "description": "match on required clause, product of:",
                            "details": [
                                {
                                    "value": 0,
                                    "description": "# clause",
                                    "details": []
                                },
                                {
                                    "value": 0.35959372,
                                    "description": "_type:user, product of:",
                                    "details": [
                                        {
                                            "value": 1,
                                            "description": "boost",
                                            "details": []
                                        },
                                        {
                                            "value": 0.35959372,
                                            "description": "queryNorm",
                                            "details": []
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            },
            ......
        ]
    }
}

你可以看到,不仅是“魔都大街”的记录被查询出来了,只要有“大街”的记录也被查出来了哦。同时,也告诉了你,为什么”u002″是最靠前的。

还有一种用法,就是让ES告诉你,查询语句哪里错了:

curl -XPOST http://127.0.0.1:9200/myindex/user/_validate/query?explain -d'
{
   "query"   : { "matchA" : { "家庭住址" : "魔都大街" }}
}'

{
    "valid": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "failed": 0
    },
    "explanations": [
        {
            "index": "myindex",
            "valid": false,
            "error": "org.elasticsearch.index.query.QueryParsingException: No query registered for [matchA]"
        }
    ]
}

ES会告诉你matchA这里错了哦。

ElasticSearch2基本操作(04关于分词)

恩,有些初步的感觉了没?那回过头来我们看下最基础的东西:

ES中,常见数据类型如下:

类型名称 数据类型
字符串 string
整数 byte, short, integer, long
浮点数 float, double
布尔 boolean
日期 date
对象 object
嵌套结构 nested
地理位置(经纬度) geo_point

常用字段分析类型如下:

分析类型 含义
analyzed 首先分析这个字符串,然后索引。换言之,以全文形式索引此字段。
not_analyzed 索引这个字段,使之可以被搜索,但是索引内容和指定值一样。不分析此字段。
no 不索引这个字段。这个字段不能被搜索到。

然后,我们测试一下分词器

1、首先测试一下用标准分词进行分词

curl -XPOST http://localhost:9200/_analyze?analyzer=standard&text=小明同学大吃一惊

{
    "tokens": [
        {
            "token": "小",
            "start_offset": 0,
            "end_offset": 1,
            "type": "<IDEOGRAPHIC>",
            "position": 0
        },
        {
            "token": "明",
            "start_offset": 1,
            "end_offset": 2,
            "type": "<IDEOGRAPHIC>",
            "position": 1
        },
        {
            "token": "同",
            "start_offset": 2,
            "end_offset": 3,
            "type": "<IDEOGRAPHIC>",
            "position": 2
        },
        {
            "token": "学",
            "start_offset": 3,
            "end_offset": 4,
            "type": "<IDEOGRAPHIC>",
            "position": 3
        },
        {
            "token": "大",
            "start_offset": 4,
            "end_offset": 5,
            "type": "<IDEOGRAPHIC>",
            "position": 4
        },
        {
            "token": "吃",
            "start_offset": 5,
            "end_offset": 6,
            "type": "<IDEOGRAPHIC>",
            "position": 5
        },
        {
            "token": "一",
            "start_offset": 6,
            "end_offset": 7,
            "type": "<IDEOGRAPHIC>",
            "position": 6
        },
        {
            "token": "惊",
            "start_offset": 7,
            "end_offset": 8,
            "type": "<IDEOGRAPHIC>",
            "position": 7
        }
    ]
}

2、然后对比一下用IK分词进行分词

curl -XGET http://localhost:9200/_analyze?analyzer=ik&text=小明同学大吃一惊

{
    "tokens": [
        {
            "token": "小明",
            "start_offset": 0,
            "end_offset": 2,
            "type": "CN_WORD",
            "position": 0
        },
        {
            "token": "同学",
            "start_offset": 2,
            "end_offset": 4,
            "type": "CN_WORD",
            "position": 1
        },
        {
            "token": "大吃一惊",
            "start_offset": 4,
            "end_offset": 8,
            "type": "CN_WORD",
            "position": 2
        },
        {
            "token": "大吃",
            "start_offset": 4,
            "end_offset": 6,
            "type": "CN_WORD",
            "position": 3
        },
        {
            "token": "吃",
            "start_offset": 5,
            "end_offset": 6,
            "type": "CN_WORD",
            "position": 4
        },
        {
            "token": "一惊",
            "start_offset": 6,
            "end_offset": 8,
            "type": "CN_WORD",
            "position": 5
        },
        {
            "token": "一",
            "start_offset": 6,
            "end_offset": 7,
            "type": "TYPE_CNUM",
            "position": 6
        },
        {
            "token": "惊",
            "start_offset": 7,
            "end_offset": 8,
            "type": "CN_CHAR",
            "position": 7
        }
    ]
}

3、测试一下按”家庭住址”字段进行分词

curl -XGET http://localhost:9200/myindex/_analyze?field=家庭住址&text=我爱北京天安门

{
    "tokens": [
        {
            "token": "我",
            "start_offset": 0,
            "end_offset": 1,
            "type": "CN_CHAR",
            "position": 0
        },
        {
            "token": "爱",
            "start_offset": 1,
            "end_offset": 2,
            "type": "CN_CHAR",
            "position": 1
        },
        {
            "token": "北京",
            "start_offset": 2,
            "end_offset": 4,
            "type": "CN_WORD",
            "position": 2
        },
        {
            "token": "京",
            "start_offset": 3,
            "end_offset": 4,
            "type": "CN_WORD",
            "position": 3
        },
        {
            "token": "天安门",
            "start_offset": 4,
            "end_offset": 7,
            "type": "CN_WORD",
            "position": 4
        },
        {
            "token": "天安",
            "start_offset": 4,
            "end_offset": 6,
            "type": "CN_WORD",
            "position": 5
        },
        {
            "token": "门",
            "start_offset": 6,
            "end_offset": 7,
            "type": "CN_CHAR",
            "position": 6
        }
    ]
}

4、测试一下按”性别”字段进行分词

curl -XGET http://localhost:9200/myindex/_analyze?field=性别&text=我爱北京天安门

{
    "tokens": [
        {
            "token": "我爱北京天安门",
            "start_offset": 0,
            "end_offset": 7,
            "type": "word",
            "position": 0
        }
    ]
}

大家可以看到,不同的分词器,使用场景、针对语言是不一样的,所以要选择合适的分词器。
此外,对于不同的字段,要选择不同的分析方式及适用的分词器,会让你事半功倍。

ElasticSearch2基本操作(03增删改查REST)

接上一篇:

11、更新文档

curl -XPOST http://localhost:9200/_bulk -d'
{ action: { metadata }}\n
{ request body        }\n
{ action: { metadata }}\n
{ request body        }\n
'
操作类型 说明
create 当文档不存在时创建之。
index 创建新文档或替换已有文档。
update 局部更新文档。
delete 删除一个文档。

比如下面的操作:
首先删除一个文件
再新建一个文件
然后全局更加一个文件
最后局部更新一个文件

curl -XPOST http://localhost:9200/_bulk -d'
{ "delete": { "_index": "myindex", "_type": "user", "_id": "u004" }}
{ "create": { "_index": "myindex", "_type": "user", "_id": "u004" }}
{"用户ID": "u004","姓名":"赵六","性别":"男","年龄":"27","家庭住址":"深圳市龙岗区特区大街011号","注册时间":"2015-04-01 08:30:00"}
{ "index": { "_index": "myindex", "_type": "user", "_id": "u004" }}
{"用户ID": "u004","姓名":"赵六","性别":"男","年龄":"28","家庭住址":"深圳市龙岗区特区大街012号","注册时间":"2015-04-01 08:30:00"}
{ "update": { "_index": "myindex", "_type": "user", "_id": "u004"} }
{ "doc" : {"年龄" : "28"}}

结果如下:(局部更新没有执行,没查到原因)

{
    "took": 406,
    "errors": false,
    "items": [
        {
            "delete": {
                "_index": "myindex",
                "_type": "user",
                "_id": "u004",
                "_version": 10,
                "_shards": {
                    "total": 2,
                    "successful": 1,
                    "failed": 0
                },
                "status": 200,
                "found": true
            }
        },
        {
            "create": {
                "_index": "myindex",
                "_type": "user",
                "_id": "u004",
                "_version": 11,
                "_shards": {
                    "total": 2,
                    "successful": 1,
                    "failed": 0
                },
                "status": 201
            }
        },
        {
            "index": {
                "_index": "myindex",
                "_type": "user",
                "_id": "u004",
                "_version": 12,
                "_shards": {
                    "total": 2,
                    "successful": 1,
                    "failed": 0
                },
                "status": 200
            }
        }
    ]
}

ElasticSearch2基本操作(02增删改查REST)

接上一篇:

7、更新文档

#新增u004
curl -XPUT http://localhost:9200/myindex/user/u004 -d'
{
"用户ID": "u004",
"姓名":"赵六",
"性别":"男",
"年龄":"27",
"家庭住址":"深圳市龙岗区特区大街011号",
"注册时间":"2015-04-01 08:30:00"
}'

#更新u004
curl -XPUT http://localhost:9200/myindex/user/u004 -d'
{
"用户ID": "u004",
"姓名":"赵六",
"性别":"男",
"年龄":"27",
"家庭住址":"深圳市龙岗区特区大街011号",
"注册时间":"2015-04-01 08:30:00"
}'

#强制新增u004,如果已存在,则会报错
curl -XPUT http://localhost:9200/myindex/user/u004/_create -d'
{
"用户ID": "u004",
"姓名":"赵六",
"性别":"男",
"年龄":"27",
"家庭住址":"深圳市龙岗区特区大街012号",
"注册时间":"2015-04-01 08:30:00"
}'

返回结果如下:

#新增成功,版本为1
{
    "_index": "myindex",
    "_type": "user",
    "_id": "u004",
    "_version": 1,
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "created": true
}

#更新成功,版本为2
{
    "_index": "myindex",
    "_type": "user",
    "_id": "u004",
    "_version": 2,
    "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
    },
    "created": false
}

#强制新增失败
Http Error: Conflict

8、删除文档,注意版本号变化

#删除文档
curl -XDELETE http://localhost:9200/myindex/user/u004

9、然后新增,再做局部更新,注意版本号变化

#新增
curl -XPUT http://localhost:9200/myindex/user/u004 -d'
{
"用户ID": "u004",
"姓名":"赵六",
"性别":"男",
"年龄":"27",
"家庭住址":"深圳市龙岗区特区大街011号",
"注册时间":"2015-04-01 08:30:00"
}'

#局部更新
curl -XPOST http://localhost:9999/myindex/user/u004/_update -d'
{
    "doc": {
        "家庭住址": "深圳市龙岗区特区大街013号"
    }
}'

#取回
curl -XGET http://localhost:9999/myindex/user/u004

10、批量取回

#从index开始指定
curl -XGET http://localhost:9999/_mget'
{
   "docs" : [
      {
         "_index" : "myindex",
         "_type" :  "user",
         "_id" :    "u001"
      },
      {
         "_index" : "myindex",
         "_type" :  "user",
         "_id" :    "u002",
         "_source": "家庭住址"
      }
   ]
}'

#index相同
GET -XGET http://localhost:9999/myindex/_mget'
{
   "docs" : [
      {  "_type" : "user", "_id" :   "u002"},
      { "_type" : "user", "_id" :   "u002" }
   ]
}'

#type相同
curl -XGET http://localhost:9999/myindex/user/_mget'
{
   "ids" : [ "u001", "u002" ]
}'

ElasticSearch2基本操作(01增删改查REST)

首先,大家要调整一下概念,对应于普通的关系型数据库,你可以暂时这样考虑

Relational DB Elasticsearch
Databases Indexes
Tables Types
Rows Documents
Columns Fields

1、创建索引myindex

curl -XPUT http://localhost:9200/myindex

2、创建类型user

curl -XPOST http://localhost:9200/myindex/user/_mapping -d'
{
    "user": {
        "_all": {
            "analyzer": "ik_max_word",
            "search_analyzer": "ik_max_word",
            "term_vector": "no",
            "store": "false"
        },
        "properties": {
            "用户ID": {
                "type": "string",
                "store": "no",
                "analyzer": "keyword",
                "search_analyzer": "keyword",
                "include_in_all": "true",
                "boost": 8
            },
            "姓名": {
                "type": "string",
                "store": "no",
                "term_vector": "with_positions_offsets",
                "analyzer": "ik_max_word",
                "search_analyzer": "ik_max_word",
                "include_in_all": "true",
                "boost": 8
            },
            "性别": {
                "type": "string",
                "store": "no",
                "analyzer": "keyword",
                "search_analyzer": "keyword",
                "include_in_all": "true",
                "boost": 8
            },
            "年龄": {
                "type": "integer",
                "store": "no",
                "index": "not_analyzed",
                "include_in_all": "true",
                "boost": 8
            },
            "家庭住址": {
                "type": "string",
                "store": "no",
                "term_vector": "with_positions_offsets",
                "analyzer": "ik_max_word",
                "search_analyzer": "ik_max_word",
                "include_in_all": "true",
                "boost": 8
            },
            "注册时间": {
                "type": "date",
                "format": "yyy-MM-dd HH:mm:ss",
                "store": "no",
                "index": "not_analyzed",
                "include_in_all": "true",
                "boost": 8
            }
        }
    }
}'

在这里类型user中,有几种索引类型,

key 类型 分词方式
用户ID string keyword
姓名 string ik_max_word
性别 string keyword
年龄 integer not_analyzed
家庭住址 string ik_max_word
注册时间 date not_analyzed

其中,
ik_max_word,指的是用ik分词,然后将分词结果作为term,需要分词检索的字段,需要这样处理
keyword,指的是,不要分词,而是把整个词作为term,ID及字典很适合这样做
not_analyzed,是不做分词处理,如数字、时间,没有必要

3、上传文档

curl -XPUT http://localhost:9200/myindex/user/u001 -d'
{
"用户ID": "u001",
"姓名":"张三",
"性别":"男",
"年龄":"25",
"家庭住址":"北京市崇文区天朝大街001号",
"注册时间":"2015-01-01 08:30:00"
}'

curl -XPUT http://localhost:9200/myindex/user/u002 -d'
{
"用户ID": "u002",
"姓名":"李四",
"性别":"男",
"年龄":"25",
"家庭住址":"上海市闸北区魔都大街007号",
"注册时间":"2015-02-01 08:30:00"
}'

curl -XPUT http://localhost:9200/myindex/user/u003 -d'
{
"用户ID": "u003",
"姓名":"王五",
"性别":"男",
"年龄":"26",
"家庭住址":"广州市花都区花城大街010号",
"注册时间":"2015-03-01 08:30:00"
}'

4、文档是否存在

#判断id为u003的文档是否存在
curl -XHEAD http://localhost:9200/myindex/user/u003

5、获取文档

#获取id为u003的文档
curl -XGET http://localhost:9200/myindex/user/u003

#获取id为u003的文档的姓名及性别字段
http://localhost:9200/myindex/user/u003?_source=姓名,性别

6、查询文档

#查询文档,默认返回前10个
curl -XGET http://localhost:9200/myindex/user/_search

#用参数进行查询
#年龄等于25的记录
curl -XGET http://localhost:9200/myindex/user/_search?q=年龄:25
#姓名等于王五的记录
curl -XGET http://localhost:9200/myindex/user/_search?q=姓名:王五
#姓名等于王五及年龄等于25的记录
curl -XGET http://localhost:9200/myindex/user/_search?q=+姓名:王五+年龄:26

#查询年龄等于25的用户
curl -XGET http://localhost:9200/myindex/user/_search -d'
{
    "query" : {
        "match" : {
            "年龄" : "25"
        }
    }
}'

#查询年龄大于25,男性用户
curl -XGET http://localhost:9200/myindex/user/_search -d'
{
    "query": {
        "filtered": {
            "filter": {
                "range": {
                    "年龄": {
                        "gt": 25
                    }
                }
            },
            "query": {
                "match": {
                    "性别": "男"
                }
            }
        }
    }
}'

#查询家庭住址中,包含北京或上海的用户
curl -XGET http://localhost:9200/myindex/user/_search -d'
{
    "query" : {
        "match" : {
            "家庭住址" : "北京 上海"
        }
    }
}'

#查询词组
curl -XGET http://localhost:9200/myindex/user/_search -d'
{
    "query" : {
        "match_phrase" : {
            "家庭住址" : "北京 崇文"
        }
    }
}

#按年龄分组聚合,并count
curl -XGET http://localhost:9200/myindex/user/_search -d'
{
  "aggs": {
    "all_interests": {
      "terms": { "field": "年龄" }
    }
  }
}

#男性患者,按年龄分组聚合,并count
curl -XGET http://localhost:9200/myindex/user/_search -d'
{
  "query": {
    "match": {
      "性别": "男"
    }
  },
  "aggs": {
    "all_interests": {
      "terms": {
        "field": "年龄"
      }
    }
  }
}

ElasticSearch2常用插件

1、在线安装常用插件

#head
bin\plugin install mobz/elasticsearch-head

#gui
bin\plugin install jettro/elasticsearch-gui

#bigdesk
#bin\plugin install lukas-vlcek/bigdesk
bin\plugin install hlstudio/bigdesk

#kopf
bin\plugin install lmenezes/elasticsearch-kopf

#carrot2
bin\plugin install org.carrot2/elasticsearch-carrot2/2.2.1

#inquisitor
bin\plugin install polyfractal/elasticsearch-inquisitor

2、离线安装常用插件

#上面的插件,都可手工下载后,通过命令行进行离线安装
bin\plugin install file:///PATH_TO_PLUGIN/PLUGIN.zip

3、手工安装分词插件

#到下面的地址下载release版本,解压,放到ES的plugins目录下,然后重启即可
https://github.com/medcl/elasticsearch-analysis-ik
https://github.com/medcl/elasticsearch-analysis-pinyin
https://github.com/medcl/elasticsearch-analysis-mmseg