Elasticsearch 讲解及 Java 应用实战:从入门到落地

在数据量爆炸的今天,传统数据库的查询能力越来越难以满足复杂的检索需求。比如电商平台的商品搜索,需要支持关键词模糊匹配、多条件筛选、热门度排序等功能,这时候 Elasticsearch(简称 ES)就成了最佳选择。作为一款分布式全文搜索引擎,ES 以其强大的检索能力、灵活的扩展性被广泛应用。本文将从 ES 核心概念讲起,结合 Java 实战案例,带你快速掌握 ES 的应用技巧。

一、Elasticsearch 核心概念与优势

在使用 ES 前,我们需要先理清它的核心概念 —— 很多人会把 ES 和数据库类比,这个思路其实很实用。

1.1 ES 与关系型数据库的概念对应

如果把 ES 比作数据库,两者的核心概念可以这样对应:

关系型数据库

Elasticsearch

说明

Database(数据库)

Index(索引)

一个索引对应一类数据集合,比如 “商品索引”“用户索引”

Table(表)

Type(类型)

早期 ES 用于区分索引内的不同数据类型,7.x 后已废弃,一个索引只对应一种类型

Row(行)

Document(文档)

索引中的一条数据,以 JSON 格式存储

Column(列)

Field(字段)

文档中的一个属性,比如商品的 “名称”“价格”

Schema(表结构)

Mapping(映射)

定义文档中字段的类型、分词器等规则

1.2 ES 的核心优势

相比传统数据库和其他搜索引擎,ES 的核心竞争力体现在这几点:

  • 全文检索能力:支持关键词分词、模糊匹配、同义词扩展等,比如搜索 “手机” 时能匹配 “智能手机”“移动电话”。
  • 分布式架构:天然支持分片和副本,数据自动分片存储,副本保证高可用,可轻松扩展至海量数据。
  • 近实时搜索:数据写入后秒级可查,兼顾实时性和性能。
  • 灵活的聚合分析:支持统计、排序、分组等复杂分析,比如按 “商品分类” 统计销量 Top10。

二、Elasticsearch 核心操作入门

要使用 ES,首先要掌握其基础操作。ES 提供 RESTful API 接口,可通过 HTTP 请求直接操作,也可通过客户端工具(如 Kibana 的 Dev Tools)执行。

2.1 索引相关操作

(1)创建索引及映射

创建一个 “商品索引”,并定义字段映射(类似数据库建表时定义字段类型):

# 创建商品索引

PUT /product_index

{

"mappings": {

"properties": {

"id": { "type": "keyword" }, // 商品ID,精确匹配,不分词

"name": {

"type": "text",

"analyzer": "ik_max_word", // 使用IK分词器(中文分词必备)

"fields": {

"keyword": { "type": "keyword" } // 用于精确查询或排序

}

},

"price": { "type": "double" }, // 价格

"category": { "type": "keyword" }, // 分类,精确匹配

"createTime": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss" } // 创建时间

}

}

}

这里有两个关键注意点:

  • text 与 keyword:text类型用于全文检索(会分词),keyword用于精确匹配(不分词),同一个字段可通过fields同时支持两种类型。
  • 中文分词:必须使用 IK 分词器(需提前安装),ik_max_word会将文本拆分为最细粒度(如 “华为手机” 拆为 “华为”“手机”),ik_smart为粗粒度拆分。
(2)查看索引映射

GET /product_index/_mapping

(3)删除索引

DELETE /product_index

2.2 文档相关操作

文档是 ES 中最小的数据单元,所有操作围绕文档展开。

(1)新增文档

# 新增文档(指定ID)

PUT /product_index/_doc/1001

{

"id": "1001",

"name": "华为Mate 60 Pro 智能手机",

"price": 6999.00,

"category": "手机",

"createTime": "2024-01-15 09:30:00"

}

# 新增文档(自动生成ID)

POST /product_index/_doc

{

"id": "1002",

"name": "苹果iPhone 15 手机",

"price": 7999.00,

"category": "手机",

"createTime": "2024-01-20 14:20:00"

}

(2)查询文档

ES 的查询能力非常强大,这里列举几种常用场景:

  • 精确查询(根据分类查询手机商品):

GET /product_index/_search

{

"query": {

"term": {

"category": { "value": "手机" }

}

}

}

  • 全文检索(搜索包含 “华为” 的商品):

GET /product_index/_search

{

"query": {

"match": {

"name": "华为"

}

}

}

  • 组合条件查询(价格在 5000-8000,且分类为手机):

GET /product_index/_search

{

"query": {

"bool": {

"must": [

{ "term": { "category": "手机" } },

{ "range": { "price": { "gte": 5000, "lte": 8000 } } }

]

}

},

"sort": [{"createTime": "desc"}], // 按创建时间倒序

"from": 0, "size": 10 // 分页(从第0条开始,取10条)

}

(3)更新与删除文档
  • 更新文档(全量更新或局部更新):

# 局部更新(只更新价格)

POST /product_index/_update/1001

{

"doc": {

"price": 6799.00

}

}

  • 删除文档

DELETE /product_index/_doc/1001

三、Java 操作 Elasticsearch 实战

实际开发中,我们很少直接调用 REST API,而是通过官方客户端工具操作。ES 官方推荐的 Java 客户端是 Elasticsearch Java Client(7.x 后替代了旧的 Transport Client)。

3.1 环境准备

(1)引入依赖

在 Maven 项目的pom.xml中添加依赖(版本需与 ES 服务器一致,这里以 8.10.4 为例):

<dependencies>

<!-- Elasticsearch Java Client -->

<dependency>

<groupId>co.elastic.clients</groupId>

<artifactId>elasticsearch-java</artifactId>

<version>8.10.4</version>

</dependency>

<!-- 依赖Jackson处理JSON -->

<dependency>

<groupId>com.fasterxml.jackson.core</groupId>

<artifactId>jackson-databind</artifactId>

<version>2.15.2</version>

</dependency>

<!-- 连接池 -->

<dependency>

<groupId>org.apache.httpcomponents.client5</groupId>

<artifactId>httpclient5</artifactId>

<version>5.3</version>

</dependency>

</dependencies>

(2)初始化客户端

创建 ES 客户端连接(类似数据库连接池):

import co.elastic.clients.elasticsearch.ElasticsearchClient;

import co.elastic.clients.json.jackson.JacksonJsonpMapper;

import co.elastic.clients.transport.ElasticsearchTransport;

import co.elastic.clients.transport.rest_client.RestClientTransport;

import org.apache.http.HttpHost;

import org.elasticsearch.client.RestClient;

public class EsClient {

// 单例客户端

private static ElasticsearchClient client;

static {

// 创建REST客户端(连接ES服务器,可配置多个节点)

RestClient restClient = RestClient.builder(

new HttpHost("localhost", 9200, "http")

).build();

// 创建传输层

ElasticsearchTransport transport = new RestClientTransport(

restClient, new JacksonJsonpMapper()

);

// 创建客户端

client = new ElasticsearchClient(transport);

}

public static ElasticsearchClient getClient() {

return client;

}

}

注意:ES 客户端版本必须与服务器版本保持一致,否则可能出现兼容性问题。

3.2 核心操作实战:商品搜索功能

以 “电商商品搜索” 为例,实现文档新增、条件查询、分页排序等核心功能。

(1)定义商品实体类

import com.fasterxml.jackson.annotation.JsonFormat;

import lombok.Data;

import java.util.Date;

@Data

public class Product {

private String id;

private String name;

private Double price;

private String category;

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")

private Date createTime;

}

(2)新增商品文档

import co.elastic.clients.elasticsearch.ElasticsearchClient;

import co.elastic.clients.elasticsearch.core.IndexRequest;

import co.elastic.clients.elasticsearch.core.IndexResponse;

import java.io.IOException;

public class ProductService {

private final ElasticsearchClient client = EsClient.getClient();

// 新增商品到ES

public void addProduct(Product product) throws IOException {

// 构建索引请求(指定索引名、文档ID和数据)

IndexRequest<Product> request = IndexRequest.of(b -> b

.index("product_index") // 索引名

.id(product.getId()) // 文档ID(可选,不指定则自动生成)

.document(product) // 文档数据

);

// 执行请求

IndexResponse response = client.index(request);

System.out.println("新增结果:" + response.result());

}

}

(3)多条件查询商品

实现一个带条件、分页、排序的商品搜索功能:

import co.elastic.clients.elasticsearch.core.SearchRequest;

import co.elastic.clients.elasticsearch.core.SearchResponse;

import co.elastic.clients.elasticsearch.core.search.Hit;

import co.elastic.clients.elasticsearch.core.search.TotalHits;

import co.elastic.clients.elasticsearch.core.search.TotalHitsRelation;

import java.io.IOException;

import java.util.ArrayList;

import java.util.List;

public class ProductService {

// ... 其他代码省略

/**

* 搜索商品

* @param keyword 关键词(搜索商品名称)

* @param category 分类(可选)

* @param minPrice 最低价格(可选)

* @param maxPrice 最高价格(可选)

* @param page 页码(从1开始)

* @param size 每页条数

* @return 商品列表及总条数

*/

public SearchResult<Product> searchProducts(String keyword, String category,

Double minPrice, Double maxPrice,

int page, int size) throws IOException {

// 构建查询条件

SearchRequest request = SearchRequest.of(b -> b

.index("product_index") // 指定索引

.query(q -> q

.bool(bool -> {

// 拼接查询条件

if (keyword != null && !keyword.isEmpty()) {

// 全文检索商品名称

bool.must(m -> m.match(t -> t.field("name").query(keyword)));

}

if (category != null && !category.isEmpty()) {

// 精确匹配分类

bool.filter(f -> f.term(t -> t.field("category").value(category)));

}

if (minPrice != null || maxPrice != null) {

// 价格范围过滤

bool.filter(f -> f.range(r -> {

if (minPrice != null) r.gte(minPrice);

if (maxPrice != null) r.lte(maxPrice);

return r.field("price");

}));

}

return bool;

})

)

.sort(s -> s.field(f -> f.field("createTime").order("desc"))) // 按创建时间倒序

.from((page - 1) * size) // 起始位置(分页)

.size(size) // 每页条数

);

// 执行查询

SearchResponse<Product> response = client.search(request, Product.class);

// 处理结果

List<Product> products = new ArrayList<>();

for (Hit<Product> hit : response.hits().hits()) {

products.add(hit.source()); // 获取文档数据

}

// 总条数

TotalHits totalHits = response.hits().total();

long total = 0;

if (totalHits != null && totalHits.relation() == TotalHitsRelation.Eq) {

total = totalHits.value();

}

return new SearchResult<>(total, products);

}

// 定义结果封装类

@Data

public static class SearchResult<T> {

private long total; // 总条数

private List<T> data; // 数据列表

public SearchResult(long total, List<T> data) {

this.total = total;

this.data = data;

}

}

}

这个方法包含了 ES 查询的核心场景:

  • 多条件组合:用bool查询拼接 “必须满足(must)” 和 “过滤(filter)” 条件;
  • 全文检索:match查询用于商品名称的关键词搜索;
  • 精确匹配与范围过滤:term查询匹配分类,range查询过滤价格;
  • 分页与排序:通过from、size实现分页,sort指定排序规则。

3.3 性能优化技巧

在实际应用中,ES 的性能优化不可忽视,尤其是数据量大或查询频繁的场景:

  1. 合理设计映射
    • 不需要检索的字段设置index: false(如商品详情的大文本);
    • 精确匹配字段用keyword类型,避免text类型的不必要分词。
  1. 优化查询语句
    • 用filter代替must(filter不计算评分,且可缓存结果);
    • 避免wildcard前缀匹配(如name:*手机),会导致全表扫描;
    • 分页查询时,深分页(如from:10000)改用search_after。
  1. 索引分片优化
    • 初始分片数设置为 “节点数 ×1~3”(如 3 个节点可设 5 个分片);
    • 分片大小控制在 20GB~50GB 之间,过大影响查询性能。
  1. 批量操作

// 批量新增示例

BulkRequest.Builder bulk = new BulkRequest.Builder();

for (Product product : productList) {

bulk.operations(op -> op

.index(idx -> idx

.index("product_index")

.id(product.getId())

.document(product)

)

);

}

client.bulk(bulk.build());

    • 批量新增 / 更新用BulkRequest,减少网络请求次数;

四、常见问题与解决方案

在 ES 应用中,新手容易遇到一些 “坑”,这里总结几个高频问题:

  1. 中文分词效果差
    • 原因:未安装 IK 分词器,默认分词器会把中文拆成单字;
    • 解决:在 ES 插件目录安装 IK 分词器(版本与 ES 一致),并在映射中指定analyzer: "ik_max_word"。
  1. 查询结果与预期不符
    • 检查字段类型:如果用term查询text类型字段,可能因分词导致匹配失败(需用match查询);
    • 检查分词结果:通过GET /product_index/_analyze测试字段分词效果。
  1. 写入 / 查询性能慢
    • 写入慢:检查分片副本数(初期可设 1 个副本)、是否开启批量写入;
    • 查询慢:查看是否命中索引(通过explain分析查询计划)、是否需要增加节点或优化分片。

五、总结

Elasticsearch 是一款强大的搜索引擎,其核心价值在于全文检索分布式扩展能力。本文从基础概念出发,通过 “理论 + 实战” 的方式讲解了 ES 的核心操作,并结合 Java 案例实现了商品搜索功能。

要熟练掌握 ES,关键在于:

  1. 理解索引、文档、映射等核心概念,明确text与keyword的区别;
  1. 掌握bool组合查询、范围查询、聚合分析等核心语法;
  1. 结合实际场景优化映射设计和查询语句,避免性能问题。

如果你在 ES 应用中遇到过特殊场景(如大数据量同步、复杂聚合分析),欢迎在评论区分享你的解决方案!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/916192.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/916192.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker pull weaviate 国内拉取失败的问题

我是校内网&#xff0c;尝试了 改镜像源 (cooragent) ruiyCJQ:~/sdb/B/cooragent$ sudo vim /etc/docker/daemon.json [sudo] password for ruiy: (cooragent) ruiyCJQ:~/sdb/B/cooragent$ sudo service docker restart (cooragent) ruiyCJQ:~/sdb/B/cooragent$ sudo docke…

Vue项目使用Univer Sheets

Univer Excel主页链接&#xff1a;安装步骤 1. 安装 使用预设模式的包管理器安装 - 预设模式&#xff1a;可以理解为开包即用的模式&#xff0c;省去很多配置&#xff0c;当然自由度不如插件模式 pnpm add univerjs/presets univerjs/preset-sheets-core2. 前端代码 <te…

Python day24

浙大疏锦行 python day24 内容&#xff1a; 元组&#xff1a;类比于列表&#xff0c;不过元组的元素不能被修改&#xff0c;显示也是从[]改为了()&#xff0c;其余操作则是和列表类似&#xff0c;且元组是有序的可迭代对象&#xff1a;即可以使用迭代器访问的对象&#xff0c…

Three.js 动画系统入门:Tween.js 与 AnimationMixer 的使用

引言 动画是 Three.js 中增强 3D 场景动态效果的核心技术&#xff0c;能够为用户带来沉浸式体验。Three.js 支持通过 Tween.js 实现简单的属性动画&#xff0c;以及通过 AnimationMixer 处理复杂的混合动画和骨骼动画。本文将深入探讨如何使用 Tween.js 控制 Object3D 的属性动…

装修进度管理系统功能对比:主流工具9选

本文分享了9款常用的装修进度管理软件&#xff0c;包括&#xff1a;1.Worktile&#xff1b;2.中望软件&#xff1b;3.三维家&#xff1b;4.Procore&#xff1b;5.易达装修管理系统&#xff1b;6.装修管家&#xff1b;7.Zoho Projects&#xff1b;8.中建君联&#xff1b;9.一品装…

深度学习篇---预训练模型

在深度学习中&#xff0c;预训练模型&#xff08;Pretrained Model&#xff09; 是提升开发效率和模型性能的 “利器”。无论是图像识别、自然语言处理还是语音识别&#xff0c;预训练模型都被广泛使用。下面从概念、使用原因、场景、作用等方面详细介绍&#xff0c;并结合 Pyt…

Redis ①⑦-分布式锁

分布式锁 分布式锁是锁的一种&#xff0c;都是为了解决多线程/多进程环境下&#xff0c;对共享资源的访问冲突问题。 不过&#xff0c;像 Java 的 synchronized 或者 C 的 mutex 这种锁&#xff0c;都是进程内的锁&#xff0c;而分布式锁则是跨越进程/机器的锁。也就是可以针对…

OpenCV-图像预处理➀【图像颜色空间转换、灰度化实验、二值化处理、镜像翻转 和 仿射变换】

文章目录先言一、图像颜色空间转换1.RGB颜色空间2.颜色加法3.颜色加权加法4.HSV颜色空间5.图像转换&#xff08;cvtColor()&#xff09;二、灰度实验1.灰度图2.图像灰度化&#xff08;最大值法&#xff09;3.图像灰度化&#xff08;平均值法&#xff09;4.图像灰度化&#xff0…

APP逆向 day9 安卓开发基础

一.前言 app逆向当然要学安卓基础啦&#xff01;今天我们来教安卓基础当然&#xff0c;安卓基础不会教的很多&#xff0c;比java还要少&#xff0c;还是那句话&#xff0c;了解就好。 二.安卓环境搭建 2.1 安卓介绍 如果做安卓开发 需要会java代码安卓SDK(安卓提供的内置…

Jmeter的元件使用介绍:(三)配置元件详解02

六、计数器 可以用来做一些变量自增操作。 1、Starting value:定义初始值 2、递增&#xff1a;定义每次执行递增多少 3、Maximum value:定义承受的最大值 4、数据格式&#xff1a;可以不填&#xff0c;也可以定义成000;001;002等等任意格式都行。&#xff08;1&#xff09;如…

JavaWeb学习打卡15(JSP标签、JSTL标签、EL表达式)

EL表达式&#xff1a;${ }获取数据执行运算获取web开发的常用对象在pom.xml 文件中导入JSP、JSTL相关依赖&#xff1a;<!--JSP依赖--><!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api --><dependency><groupId>java…

7.22数据结构——顺序表

文章目录一、思维导图二、实现顺序表的功能代码head.htest.cmain.c一、思维导图 二、实现顺序表的功能代码 head.h #ifndef __HEAD_H__ #define __HEAD_H__#include <stdio.h> #include <string.h> #include <stdlib.h> //数组的最大长度 #define MAXSIZE …

【如何无限制免费试用 IDEA || Pycharm(JB 全家桶)】

如何无限制免费试用 IDEA || Pycharm(JB 全家桶) 一、目标:解决 JB 全家桶试用时长痛点 如果你是程序员,大概率用过 JetBrains 家的 IDE——IDEA 写 Java、Pycharm 写 Python、WebStorm 做前端,体验确实顶流,但官方 30 天试用到期后,动辄几千的年费实在让人肉痛。 咱…

Qt(资源库和按钮组)

这一节是对上一节的补充&#xff0c;上一节提到QLabel类和QAabstractButton类&#xff0c;这节内容&#xff1a;1.如设置资源库&#xff0c;使用资源设置图片2. 使用按钮组管理多个按钮。一、资源库1. 资源库作用Qt的资源库&#xff08;Resource System&#xff0c;.qrc文件&am…

一道检验编码能力的字符串的题目

#include<iostream> #include<vector> #include<string> using namespace std; int bNum0,gNum0; int findEnd(string& s,int si){int lens.size();//当前字母在哪个字符串中,存入comp中string comp;if(s[si]b||s[si]o||s[si]y){comp"boy";bNu…

UniApp X 网络请求避坑指南:从 JS 到 UTS 的 JSON 数据处理全解析

在 UniApp 开发中&#xff0c;我们经常需要通过 uni.request 获取服务器返回的 JSON 数据&#xff0c;并将其绑定到页面或进行逻辑处理。但在 UniApp X&#xff08;基于 UTS&#xff09; 中&#xff0c;由于引入了 强类型语言特性&#xff0c;处理 JSON 数据的方式与 JS 有明显…

iOS 网络请求常用依赖库与系统自带 API 介绍与示例

iOS 网络请求常用依赖库与系统自带 API 介绍与示例 在 iOS 开发中&#xff0c;进行网络请求是几乎所有应用都不可或缺的功能。开发者有多种选择来处理网络通信&#xff0c;从系统自带的 URLSession 到各种流行的第三方库。下面我将为您介绍 URLSession、AFNetworking、Alamofir…

JavaScript 中 let 在循环中的作用域机制解析

一、let在循环中的特殊性 let作为ES6引入的块级作用域声明&#xff0c;在循环结构中存在特殊行为&#xff0c;其核心区别于var的函数作用域特性。理解这一特性对于编写正确的闭包逻辑至关重要。 在 ECMAScript 规范里&#xff0c;let声明的变量具有块级作用域特性&#xff0c;这…

@Subscribe@AllowConcurrentEvents解析这两个注解

@Subscribe@AllowConcurrentEvents解析这两个注解 @Subscribe 和 @AllowConcurrentEvents 是 Guava EventBus(Google 开源的事件总线框架)中用于处理事件订阅的注解,主要用于实现组件间的解耦通信。下面分别解析: 1. @Subscribe 注解 作用:标记一个方法为事件订阅者方法,…

好看的小程序推广单页HTML源码 可用作导航页

内容目录一、详细介绍二、效果展示1.部分代码2.效果图展示三、学习资料下载一、详细介绍 响应式的小程序推广单页HTML源码。这个设计采用了现代化的UI元素&#xff0c;包含吸引人的标题、特性展示、二维码区域和行动号召按钮。 二、效果展示 1.部分代码 代码如下&#xff0…