**Elasticsearch** 是一个开源的分布式搜索和分析引擎,专为速度、扩展和 AI 应用而打造。作为一个检索平台,它可以实时存储结构化、非结构化和向量数据,提供快速的混合和向量搜索,支持可观测性与安全分析,并以高性能、高准确性和高相关性实现 AI 驱动的应用。 ## 一、安装Elasticsearch #### 1、下载安装包 官网:[Download Elasticsearch | Elastic](https://www.elastic.co/cn/downloads/elasticsearch) 博客网盘:[elasticsearch-9.2.2-windows-x86_64.zip](https://pan.soki.me/s/wXI4) 下载完成后解压到要安装的目录 将`bin`文件夹添加到环境变量中,在终端中输入`elasticsearch`启动服务 在输出日志中可以找到生成的默认密码 #### 2、修改密码 可以使用命令去修改用户的密码 ```bash elasticsearch-reset-password -u elastic ``` #### 3、乱码解决 找到ES安装目录下的`config/jvm.options`文件,在文件末尾添加`-Dfile.encoding=GBK`,重启即可 #### 4、可视化图表 `Kibana`是Elasticsearch的数据可视化和实时分析的工具,利用Elasticsearch的聚合功能,生成各种图表,如柱形图,线状图,饼图等。 ##### 下载安装 官网:[Download Kibana | Elastic](https://www.elastic.co/cn/downloads/kibana) 博客网盘:[kibana-9.2.2-windows-x86_64.zip](https://pan.soki.me/s/AnHl) 下载完成后解压到要安装的目录 ##### 修改配置 打开安装目录下的`config/kibana.yml`文件,修改下面配置 ```yml elasticsearch.hosts: ["http://localhost:9200"] # 服务器地址 i18n.locale: "zh-CN" # 中文 ```   ##### 运行 打开安装目录下的`bin`文件夹,运行`kibana.bat`开启服务 打开输出的链接`http://localhost:5601/?code=834958`  在终端中输入`elasticsearch-create-enrollment-token.bat --scope kibana`获取Token  等待完成后输入ES数据库的账号密码即可进入  #### 5、插件安装 ##### 自动安装 ```bash elasticsearch-plugin install 插件地址 ``` ##### 手动安装 将压缩包解压到安装目录的`plugins`下,重新启动数据库即可。 ##### 注意 ElasticSearch安装路径上不能有任何除英文,-,_外的特殊符号,也不能包含空格!! ##### ik分词器 下载:[Index of: analysis-ik/stable/](https://release.infinilabs.com/analysis-ik/stable/) 需要选择与自己数据库版本一致的版本,解压到安装目录下的`plugins/ik/`目录内 测试 ```bash curl -X POST "localhost:9200/_analyze" -H 'Content-Type: application/json' -d' { "analyzer": "ik_smart", "text": "在doooog学习java太棒了" } ' ``` ## 二、使用Elasticsearch 示例来自官方文档,以数据库运行在`9200`端口为例 #### 1、创建索引 **索引**是最高级别的容器,用于存储相关数据。例如,你可以有一个 `user_index`(类似于 `user_db` 数据库)来存储所有用户信息。 ##### 创建默认索引 创建一个名为 `kibana_sample_data_basics` 的新索引 ```bash curl -X PUT "localhost:9200/kibana_sample_data_basics?pretty" ``` **注意**:`pretty` 参数让返回的 JSON 更易读。 ##### 创建显式映射索引 创建具有显式映射的索引,以控制哪些字段被索引。未在映射中定义的字段仍将存储在文档的 _source 字段中,但它们不会被索引或可搜索。 ```bash curl -X PUT "localhost:9200/kibana_sample_data_basics_explicit_mapping?pretty" -H 'Content-Type: application/json' -d' { "mappings": { "dynamic": false, "properties": { "author": { "type": "text" } } } } ' ``` **注意**:由于显式映射仅索引 `author` 字段,因此按 `name` 搜索将不会返回任何结果 ##### 返回示例 响应包含索引已创建的确认信息 ```bash { "acknowledged": true, "shards_acknowledged": true, "index": "kibana_sample_data_basics" } ####################################################### { "acknowledged": true, "shards_acknowledged": true, "index": "kibana_sample_data_basics_explicit_mapping" } ``` #### 2、验证索引 验证索引是否存在 ```bash curl -X GET "localhost:9200/kibana_sample_data_basics?pretty" ``` ##### 返回示例 响应包含索引的详细信息,包括映射和设置 ```bash { "kibana_sample_data_basics": { "aliases": {}, "mappings": {}, "settings": { "index": { "routing": { "allocation": { "include": { "_tier_preference": "data_content" } } }, "number_of_shards": "1", "provided_name": "kibana_sample_data_basics", "creation_date": "1765350633172", "number_of_replicas": "1", "uuid": "WoK_XhqERwqrBanbqEjfEg", "version": { "created": "9039002" } } } } } ``` #### 3、添加数据 **文档**是基本的数据单元。在 ES 中是一个 JSON 对象,在 MySQL 中是一行数据。每个文档都有一个唯一的 ID; 可以将称为**文档**的 `JSON` 对象添加到 Elasticsearch 中,数据库会将这些文档存储在可搜索的索引中; Json数据的属性将被作为**字段**,其会根据字段内的数据自动创建其**映射**(数据类型) ##### 不带ID添加 ```bash curl -X POST "localhost:9200/kibana_sample_data_basics/_doc?pretty" -H 'Content-Type: application/json' -d' { "name": "Snow Crash", "author": "Neal Stephenson", "release_date": "1992-06-01", "page_count": 470 } ' ``` ##### 带ID添加 ```bash curl -X POST "localhost:9200/kibana_sample_data_basics/_doc/1?pretty" -H 'Content-Type: application/json' -d' { "name": "Snow Crash", "author": "Neal Stephenson", "release_date": "1992-06-01", "page_count": 470 } ' ``` ##### 返回示例 响应包含唯一的文档 `_id` 和其他元数据 ```bash { "_index": "kibana_sample_data_basics", "_id": "DTEiB5sBcDVt1ED2xkL4", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 0, "_primary_term": 1 } ``` #### 4、添加多条数据 使用 `_bulk` 端点可以在一个请求中添加多个文档,批量数据必须格式化为`换行符`分隔的 JSON(NDJSON) ##### 添加数据 以两行为一组,第一行为添加到索引的信息,第二行为文档的数据 ```bash curl -X POST "localhost:9200/_bulk?pretty" -H 'Content-Type: application/json' -d' { "index" : { "_index" : "kibana_sample_data_basics" } } {"name": "Revelation Space", "author": "Alastair Reynolds", "release_date": "2000-03-15", "page_count": 585} { "index" : { "_index" : "kibana_sample_data_basics" } } {"name": "1984", "author": "George Orwell", "release_date": "1985-06-01", "page_count": 328} { "index" : { "_index" : "kibana_sample_data_basics" } } {"name": "Fahrenheit 451", "author": "Ray Bradbury", "release_date": "1953-10-15", "page_count": 227} { "index" : { "_index" : "kibana_sample_data_basics" } } {"name": "Brave New World", "author": "Aldous Huxley", "release_date": "1932-06-01", "page_count": 268} { "index" : { "_index" : "kibana_sample_data_basics" } } {"name": "The Handmaids Tale", "author": "Margaret Atwood", "release_date": "1985-06-01", "page_count": 311} ' ``` ##### 返回示例 响应包含每个操作的成功和错误摘要 ```bash { "errors": false, "took": 0, "items": [ { "index": { "_index": "kibana_sample_data_basics", "_id": "DjElB5sBcDVt1ED2JUJh", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 1, "_primary_term": 1, "status": 201 } }, { "index": { "_index": "kibana_sample_data_basics", "_id": "DzElB5sBcDVt1ED2JUJh", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 2, "_primary_term": 1, "status": 201 } }, { "index": { "_index": "kibana_sample_data_basics", "_id": "EDElB5sBcDVt1ED2JUJh", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 3, "_primary_term": 1, "status": 201 } }, { "index": { "_index": "kibana_sample_data_basics", "_id": "ETElB5sBcDVt1ED2JUJh", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 4, "_primary_term": 1, "status": 201 } }, { "index": { "_index": "kibana_sample_data_basics", "_id": "EjElB5sBcDVt1ED2JUJh", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 5, "_primary_term": 1, "status": 201 } } ] } ``` #### 5、动态映射 添加一个包含现有文档中未出现字段的新文档时Elasticsearch会将自动为新字段创建映射。 ##### 添加字段 添加一个 `language` 字段 ```bash curl -X POST "localhost:9200/kibana_sample_data_basics/_doc?pretty" -H 'Content-Type: application/json' -d' { "name": "The Great Gatsby", "author": "F. Scott Fitzgerald", "release_date": "1925-04-10", "page_count": 180, "language": "EN" } ' ``` ##### 返回示例 响应包含文档已添加的确认信息 ```bash { "_index": "kibana_sample_data_basics", "_id": "EzEpB5sBcDVt1ED2o0Ky", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 6, "_primary_term": 1 } ``` #### 6、查看映射信息 ##### 查看映射 查看 `kibana_sample_data_basics` 索引的映射 ```bash curl -X GET "localhost:9200/kibana_sample_data_basics/_mapping?pretty" ``` ##### 返回示例 新字段 `language` 已被添加到映射中,数据类型为 `text` ```bash { "kibana_sample_data_basics": { "mappings": { "properties": { "author": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "language": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "name": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "page_count": { "type": "long" }, "release_date": { "type": "date" } } } } } ################################################################# { "kibana_sample_data_basics_explicit_mapping": { "mappings": { "dynamic": "false", "properties": { "author": { "type": "text" } } } } } ``` #### 7、搜索所有文档 ##### 搜索文档 查看某个索引中所有的文档 从 `kibana_sample_data_basics` 索引中检索所有文档 ```bash curl -X GET "localhost:9200/kibana_sample_data_basics/_search?pretty" ``` ##### 返回示例 响应包含索引中所有文档的列表 ```bash { "took": 2, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 7, "relation": "eq" }, "max_score": 1, "hits": [ { "_index": "kibana_sample_data_basics", "_id": "DTEiB5sBcDVt1ED2xkL4", "_score": 1, "_source": { "name": "Snow Crash", "author": "Neal Stephenson", "release_date": "1992-06-01", "page_count": 470 } }, { "_index": "kibana_sample_data_basics", "_id": "DjElB5sBcDVt1ED2JUJh", "_score": 1, "_source": { "name": "Revelation Space", "author": "Alastair Reynolds", "release_date": "2000-03-15", "page_count": 585 } }, { "_index": "kibana_sample_data_basics", "_id": "DzElB5sBcDVt1ED2JUJh", "_score": 1, "_source": { "name": "1984", "author": "George Orwell", "release_date": "1985-06-01", "page_count": 328 } }, { "_index": "kibana_sample_data_basics", "_id": "EDElB5sBcDVt1ED2JUJh", "_score": 1, "_source": { "name": "Fahrenheit 451", "author": "Ray Bradbury", "release_date": "1953-10-15", "page_count": 227 } }, { "_index": "kibana_sample_data_basics", "_id": "ETElB5sBcDVt1ED2JUJh", "_score": 1, "_source": { "name": "Brave New World", "author": "Aldous Huxley", "release_date": "1932-06-01", "page_count": 268 } }, { "_index": "kibana_sample_data_basics", "_id": "EjElB5sBcDVt1ED2JUJh", "_score": 1, "_source": { "name": "The Handmaids Tale", "author": "Margaret Atwood", "release_date": "1985-06-01", "page_count": 311 } }, { "_index": "kibana_sample_data_basics", "_id": "EzEpB5sBcDVt1ED2o0Ky", "_score": 1, "_source": { "name": "The Great Gatsby", "author": "F. Scott Fitzgerald", "release_date": "1925-04-10", "page_count": 180, "language": "EN" } } ] } } ``` #### 8、匹配查询文档 搜索在特定字段中包含特定值的文档 ##### 带条件搜索 ```bash curl -X GET "localhost:9200/kibana_sample_data_basics/_search?pretty" -H 'Content-Type: application/json' -d' { "query": { "match": { "name": "brave" } } } ' ``` ##### 通过ID搜索 ```bash curl -X GET "localhost:9200/kibana_sample_data_basics/_doc/ETElB5sBcDVt1ED2JUJh?pretty" ``` ##### 跨索引搜索 通过通配符`*`进行跨索引搜索 ```bash curl -X GET "localhost:9200/kibana_sample_data_basics*/_search" -H 'Content-Type: application/json' -d' { "query": { "match": { "author": "Aldous Huxley" } } } ' ``` ##### 返回示例 响应包含与搜索词 `brave` 匹配的文档列表 ```bash { "took": 1, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 1, "relation": "eq" }, "max_score": 1.484231, "hits": [ { "_index": "kibana_sample_data_basics", "_id": "ETElB5sBcDVt1ED2JUJh", "_score": 1.484231, "_source": { "name": "Brave New World", "author": "Aldous Huxley", "release_date": "1932-06-01", "page_count": 268 } } ] } } ``` #### 9、删除索引 **删除索引将`永久`删除其文档、分片和元数据。** ```bash curl -X DELETE "localhost:9200/kibana_sample_data_basics" ``` ##### 返回示例 响应包含索引已被删除的确认信息 ```bash { "acknowledged": true } ``` ## 三、SpringBoot使用ES #### 1、修改ES设置 打开安装目录下`config/elasticsearch.yml`,将`xpack.security.enabled`改为`false`,否则会拒绝HTTP请求  #### 2、添加起步依赖 将`Spring Data Elasticsearch`加入起步依赖 #### 3、修改配置 在配置文件中添加 ```yml spring: # Elasticsearch 配置 elasticsearch: uris: http://localhost:9200 # 如果有用户名密码,可以配置 username: elastic password: Hwk_TlPR+yT=XNb6BbZR ``` 或者`properties`配置 ```properties # Elasticsearch 配置 spring.elasticsearch.uris=http://localhost:9200 # 如果有用户名密码,可以配置 spring.elasticsearch.username=elastic spring.elasticsearch.password=Hwk_TlPR+yT=XNb6BbZR ``` #### 4、创建文档实体类 使用`@Document`注解映射 Elasticsearch 索引,当索引不存在时会自动创建索引 以`Product`为例,创建`po/Product.java` ```java import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.data.annotation.Id; import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.Field; import org.springframework.data.elasticsearch.annotations.FieldType; @Data @NoArgsConstructor @AllArgsConstructor @Document(indexName = "product") // 指定索引名称 public class Product { @Id // 主键 private String id; @Field(type = FieldType.Text, analyzer = "ik_max_word") // 文本类型,使用 IK 分词器 private String name; @Field(type = FieldType.Keyword) // 关键字类型,不分词 private String category; @Field(type = FieldType.Double) // 数字类型 private Double price; @Field(type = FieldType.Integer) private Integer stock; @Field(type = FieldType.Text, analyzer = "ik_max_word") private String description; } ``` #### 5、创建DAO 创建`dao/ProductRepository.java`,继承 `ElasticsearchRepository`,自动实现基础 CRUD 操作 ```java import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; import org.springframework.stereotype.Repository; import java.util.List; @Repository public interface ProductRepository extends ElasticsearchRepository { // Spring Data Elasticsearch 支持方法名查询 List findByName(String name); List findByCategory(String category); List findByPriceBetween(Double minPrice, Double maxPrice); List findByNameContaining(String keyword); } ``` #### 6、创建Service 创建`service/ProductService.java`接口 ```java import cn.doooog.esdome.po.Product; import org.springframework.data.domain.Page; import java.util.List; import java.util.Optional; public interface ProductService { Product save(Product product); Iterable saveAll(List products); Optional findById(String id); Iterable findAll(); Page findAll(int page, int size); List findByName(String name); List findByCategory(String category); List findByPriceRange(Double minPrice, Double maxPrice); List searchByKeyword(String keyword); void deleteById(String id); void deleteAll(); } ``` 创建`service/impl/ProductServiceImpl.java` ```java import cn.doooog.esdome.dao.ProductRepository; import cn.doooog.esdome.po.Product; import cn.doooog.esdome.service.ProductService; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; import java.util.List; import java.util.Optional; /** * Product Service */ @Service @RequiredArgsConstructor public class ProductServiceImpl implements ProductService { private final ProductRepository productRepository; /** * 保存商品 */ public Product save(Product product) { return productRepository.save(product); } /** * 批量保存商品 */ public Iterable saveAll(List products) { return productRepository.saveAll(products); } /** * 根据 ID 查询商品 */ public Optional findById(String id) { return productRepository.findById(id); } /** * 查询所有商品 */ public Iterable findAll() { return productRepository.findAll(); } /** * 分页查询 */ public Page findAll(int page, int size) { return productRepository.findAll(PageRequest.of(page, size)); } /** * 根据名称查询 */ public List findByName(String name) { return productRepository.findByName(name); } /** * 根据类别查询 */ public List findByCategory(String category) { return productRepository.findByCategory(category); } /** * 根据价格区间查询 */ public List findByPriceRange(Double minPrice, Double maxPrice) { return productRepository.findByPriceBetween(minPrice, maxPrice); } /** * 根据关键字模糊查询 */ public List searchByKeyword(String keyword) { return productRepository.findByNameContaining(keyword); } /** * 根据 ID 删除 */ public void deleteById(String id) { productRepository.deleteById(id); } /** * 删除所有 */ public void deleteAll() { productRepository.deleteAll(); } } ``` #### 7、创建Controller 创建`controller/ProductController.java` ```java import cn.doooog.esdome.po.Product; import cn.doooog.esdome.service.ProductService; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @RequestMapping("/api/products") @RequiredArgsConstructor public class ProductController { private final ProductService productService; /** * 添加商品 */ @PostMapping public ResponseEntity addProduct(@RequestBody Product product) { Product saved = productService.save(product); return ResponseEntity.ok(saved); } /** * 批量添加商品 */ @PostMapping("/batch") public ResponseEntity> addProducts(@RequestBody List products) { Iterable saved = productService.saveAll(products); return ResponseEntity.ok(saved); } /** * 根据 ID 查询商品 */ @GetMapping("/{id}") public ResponseEntity getProduct(@PathVariable String id) { return productService.findById(id) .map(ResponseEntity::ok) .orElse(ResponseEntity.notFound().build()); } /** * 查询所有商品 */ @GetMapping public ResponseEntity> getAllProducts() { return ResponseEntity.ok(productService.findAll()); } /** * 分页查询商品 */ @GetMapping("/page") public ResponseEntity> getProductsPage( @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "10") int size) { return ResponseEntity.ok(productService.findAll(page, size)); } /** * 根据名称查询商品 */ @GetMapping("/search/name") public ResponseEntity> searchByName(@RequestParam String name) { return ResponseEntity.ok(productService.findByName(name)); } /** * 根据类别查询商品 */ @GetMapping("/search/category") public ResponseEntity> searchByCategory(@RequestParam String category) { return ResponseEntity.ok(productService.findByCategory(category)); } /** * 根据价格区间查询商品 */ @GetMapping("/search/price") public ResponseEntity> searchByPrice( @RequestParam Double minPrice, @RequestParam Double maxPrice) { return ResponseEntity.ok(productService.findByPriceRange(minPrice, maxPrice)); } /** * 关键字模糊搜索 */ @GetMapping("/search") public ResponseEntity> search(@RequestParam String keyword) { return ResponseEntity.ok(productService.searchByKeyword(keyword)); } /** * 更新商品 */ @PutMapping("/{id}") public ResponseEntity updateProduct( @PathVariable String id, @RequestBody Product product) { product.setId(id); Product updated = productService.save(product); return ResponseEntity.ok(updated); } /** * 删除商品 */ @DeleteMapping("/{id}") public ResponseEntity deleteProduct(@PathVariable String id) { productService.deleteById(id); return ResponseEntity.noContent().build(); } /** * 删除所有商品 */ @DeleteMapping public ResponseEntity deleteAllProducts() { productService.deleteAll(); return ResponseEntity.noContent().build(); } } ``` Loading... **Elasticsearch** 是一个开源的分布式搜索和分析引擎,专为速度、扩展和 AI 应用而打造。作为一个检索平台,它可以实时存储结构化、非结构化和向量数据,提供快速的混合和向量搜索,支持可观测性与安全分析,并以高性能、高准确性和高相关性实现 AI 驱动的应用。 ## 一、安装Elasticsearch #### 1、下载安装包 官网:[Download Elasticsearch | Elastic](https://www.elastic.co/cn/downloads/elasticsearch) 博客网盘:[elasticsearch-9.2.2-windows-x86_64.zip](https://pan.soki.me/s/wXI4) 下载完成后解压到要安装的目录 <img src="https://pic.soki.me/file/piclist/image-20251210114324644-1765338204995.png" alt="image-20251210114324644" style="zoom:67%;" style=""> 将`bin`文件夹添加到环境变量中,在终端中输入`elasticsearch`启动服务 <img src="https://pic.soki.me/file/piclist/image-20251210114558245-1765338358640.png" alt="image-20251210114558245" style="zoom:67%;" style=""> 在输出日志中可以找到生成的默认密码 <img src="https://pic.soki.me/file/piclist/image-20251210115122355-1765338682725.png" alt="image-20251210115122355" style="zoom:67%;" style=""> #### 2、修改密码 可以使用命令去修改用户的密码 ```bash elasticsearch-reset-password -u elastic ``` #### 3、乱码解决 找到ES安装目录下的`config/jvm.options`文件,在文件末尾添加`-Dfile.encoding=GBK`,重启即可 <img src="https://pic.soki.me/file/piclist/image-20251210115324131-1765338804498.png" alt="image-20251210115324131" style="zoom:67%;" style=""> #### 4、可视化图表 `Kibana`是Elasticsearch的数据可视化和实时分析的工具,利用Elasticsearch的聚合功能,生成各种图表,如柱形图,线状图,饼图等。 ##### 下载安装 官网:[Download Kibana | Elastic](https://www.elastic.co/cn/downloads/kibana) 博客网盘:[kibana-9.2.2-windows-x86_64.zip](https://pan.soki.me/s/AnHl) 下载完成后解压到要安装的目录 <img src="https://pic.soki.me/file/piclist/image-20251210131037886-1765343438292.png" alt="image-20251210131037886" style="zoom:67%;" style=""> ##### 修改配置 打开安装目录下的`config/kibana.yml`文件,修改下面配置 ```yml elasticsearch.hosts: ["http://localhost:9200"] # 服务器地址 i18n.locale: "zh-CN" # 中文 ```   ##### 运行 打开安装目录下的`bin`文件夹,运行`kibana.bat`开启服务 <img src="https://pic.soki.me/file/piclist/image-20251210131710735-1765343831026.png" alt="image-20251210131710735" style="zoom:67%;" style=""> 打开输出的链接`http://localhost:5601/?code=834958`  在终端中输入`elasticsearch-create-enrollment-token.bat --scope kibana`获取Token <img src="https://pic.soki.me/file/piclist/image-20251210131939780-1765343979999.png" alt="image-20251210131939780" style="zoom:67%;" style="">  等待完成后输入ES数据库的账号密码即可进入  #### 5、插件安装 ##### 自动安装 ```bash elasticsearch-plugin install 插件地址 ``` ##### 手动安装 将压缩包解压到安装目录的`plugins`下,重新启动数据库即可。 ##### 注意 ElasticSearch安装路径上不能有任何除英文,-,_外的特殊符号,也不能包含空格!! ##### ik分词器 下载:[Index of: analysis-ik/stable/](https://release.infinilabs.com/analysis-ik/stable/) 需要选择与自己数据库版本一致的版本,解压到安装目录下的`plugins/ik/`目录内 测试 ```bash curl -X POST "localhost:9200/_analyze" -H 'Content-Type: application/json' -d' { "analyzer": "ik_smart", "text": "在doooog学习java太棒了" } ' ``` ## 二、使用Elasticsearch 示例来自官方文档,以数据库运行在`9200`端口为例 #### 1、创建索引 **索引**是最高级别的容器,用于存储相关数据。例如,你可以有一个 `user_index`(类似于 `user_db` 数据库)来存储所有用户信息。 ##### 创建默认索引 创建一个名为 `kibana_sample_data_basics` 的新索引 ```bash curl -X PUT "localhost:9200/kibana_sample_data_basics?pretty" ``` **注意**:`pretty` 参数让返回的 JSON 更易读。 ##### 创建显式映射索引 创建具有显式映射的索引,以控制哪些字段被索引。未在映射中定义的字段仍将存储在文档的 _source 字段中,但它们不会被索引或可搜索。 ```bash curl -X PUT "localhost:9200/kibana_sample_data_basics_explicit_mapping?pretty" -H 'Content-Type: application/json' -d' { "mappings": { "dynamic": false, "properties": { "author": { "type": "text" } } } } ' ``` **注意**:由于显式映射仅索引 `author` 字段,因此按 `name` 搜索将不会返回任何结果 ##### 返回示例 响应包含索引已创建的确认信息 ```bash { "acknowledged": true, "shards_acknowledged": true, "index": "kibana_sample_data_basics" } ####################################################### { "acknowledged": true, "shards_acknowledged": true, "index": "kibana_sample_data_basics_explicit_mapping" } ``` #### 2、验证索引 验证索引是否存在 ```bash curl -X GET "localhost:9200/kibana_sample_data_basics?pretty" ``` ##### 返回示例 响应包含索引的详细信息,包括映射和设置 ```bash { "kibana_sample_data_basics": { "aliases": {}, "mappings": {}, "settings": { "index": { "routing": { "allocation": { "include": { "_tier_preference": "data_content" } } }, "number_of_shards": "1", "provided_name": "kibana_sample_data_basics", "creation_date": "1765350633172", "number_of_replicas": "1", "uuid": "WoK_XhqERwqrBanbqEjfEg", "version": { "created": "9039002" } } } } } ``` #### 3、添加数据 **文档**是基本的数据单元。在 ES 中是一个 JSON 对象,在 MySQL 中是一行数据。每个文档都有一个唯一的 ID; 可以将称为**文档**的 `JSON` 对象添加到 Elasticsearch 中,数据库会将这些文档存储在可搜索的索引中; Json数据的属性将被作为**字段**,其会根据字段内的数据自动创建其**映射**(数据类型) ##### 不带ID添加 ```bash curl -X POST "localhost:9200/kibana_sample_data_basics/_doc?pretty" -H 'Content-Type: application/json' -d' { "name": "Snow Crash", "author": "Neal Stephenson", "release_date": "1992-06-01", "page_count": 470 } ' ``` ##### 带ID添加 ```bash curl -X POST "localhost:9200/kibana_sample_data_basics/_doc/1?pretty" -H 'Content-Type: application/json' -d' { "name": "Snow Crash", "author": "Neal Stephenson", "release_date": "1992-06-01", "page_count": 470 } ' ``` ##### 返回示例 响应包含唯一的文档 `_id` 和其他元数据 ```bash { "_index": "kibana_sample_data_basics", "_id": "DTEiB5sBcDVt1ED2xkL4", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 0, "_primary_term": 1 } ``` #### 4、添加多条数据 使用 `_bulk` 端点可以在一个请求中添加多个文档,批量数据必须格式化为`换行符`分隔的 JSON(NDJSON) ##### 添加数据 以两行为一组,第一行为添加到索引的信息,第二行为文档的数据 ```bash curl -X POST "localhost:9200/_bulk?pretty" -H 'Content-Type: application/json' -d' { "index" : { "_index" : "kibana_sample_data_basics" } } {"name": "Revelation Space", "author": "Alastair Reynolds", "release_date": "2000-03-15", "page_count": 585} { "index" : { "_index" : "kibana_sample_data_basics" } } {"name": "1984", "author": "George Orwell", "release_date": "1985-06-01", "page_count": 328} { "index" : { "_index" : "kibana_sample_data_basics" } } {"name": "Fahrenheit 451", "author": "Ray Bradbury", "release_date": "1953-10-15", "page_count": 227} { "index" : { "_index" : "kibana_sample_data_basics" } } {"name": "Brave New World", "author": "Aldous Huxley", "release_date": "1932-06-01", "page_count": 268} { "index" : { "_index" : "kibana_sample_data_basics" } } {"name": "The Handmaids Tale", "author": "Margaret Atwood", "release_date": "1985-06-01", "page_count": 311} ' ``` ##### 返回示例 响应包含每个操作的成功和错误摘要 ```bash { "errors": false, "took": 0, "items": [ { "index": { "_index": "kibana_sample_data_basics", "_id": "DjElB5sBcDVt1ED2JUJh", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 1, "_primary_term": 1, "status": 201 } }, { "index": { "_index": "kibana_sample_data_basics", "_id": "DzElB5sBcDVt1ED2JUJh", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 2, "_primary_term": 1, "status": 201 } }, { "index": { "_index": "kibana_sample_data_basics", "_id": "EDElB5sBcDVt1ED2JUJh", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 3, "_primary_term": 1, "status": 201 } }, { "index": { "_index": "kibana_sample_data_basics", "_id": "ETElB5sBcDVt1ED2JUJh", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 4, "_primary_term": 1, "status": 201 } }, { "index": { "_index": "kibana_sample_data_basics", "_id": "EjElB5sBcDVt1ED2JUJh", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 5, "_primary_term": 1, "status": 201 } } ] } ``` #### 5、动态映射 添加一个包含现有文档中未出现字段的新文档时Elasticsearch会将自动为新字段创建映射。 ##### 添加字段 添加一个 `language` 字段 ```bash curl -X POST "localhost:9200/kibana_sample_data_basics/_doc?pretty" -H 'Content-Type: application/json' -d' { "name": "The Great Gatsby", "author": "F. Scott Fitzgerald", "release_date": "1925-04-10", "page_count": 180, "language": "EN" } ' ``` ##### 返回示例 响应包含文档已添加的确认信息 ```bash { "_index": "kibana_sample_data_basics", "_id": "EzEpB5sBcDVt1ED2o0Ky", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 6, "_primary_term": 1 } ``` #### 6、查看映射信息 ##### 查看映射 查看 `kibana_sample_data_basics` 索引的映射 ```bash curl -X GET "localhost:9200/kibana_sample_data_basics/_mapping?pretty" ``` ##### 返回示例 新字段 `language` 已被添加到映射中,数据类型为 `text` ```bash { "kibana_sample_data_basics": { "mappings": { "properties": { "author": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "language": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "name": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "page_count": { "type": "long" }, "release_date": { "type": "date" } } } } } ################################################################# { "kibana_sample_data_basics_explicit_mapping": { "mappings": { "dynamic": "false", "properties": { "author": { "type": "text" } } } } } ``` #### 7、搜索所有文档 ##### 搜索文档 查看某个索引中所有的文档 从 `kibana_sample_data_basics` 索引中检索所有文档 ```bash curl -X GET "localhost:9200/kibana_sample_data_basics/_search?pretty" ``` ##### 返回示例 响应包含索引中所有文档的列表 ```bash { "took": 2, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 7, "relation": "eq" }, "max_score": 1, "hits": [ { "_index": "kibana_sample_data_basics", "_id": "DTEiB5sBcDVt1ED2xkL4", "_score": 1, "_source": { "name": "Snow Crash", "author": "Neal Stephenson", "release_date": "1992-06-01", "page_count": 470 } }, { "_index": "kibana_sample_data_basics", "_id": "DjElB5sBcDVt1ED2JUJh", "_score": 1, "_source": { "name": "Revelation Space", "author": "Alastair Reynolds", "release_date": "2000-03-15", "page_count": 585 } }, { "_index": "kibana_sample_data_basics", "_id": "DzElB5sBcDVt1ED2JUJh", "_score": 1, "_source": { "name": "1984", "author": "George Orwell", "release_date": "1985-06-01", "page_count": 328 } }, { "_index": "kibana_sample_data_basics", "_id": "EDElB5sBcDVt1ED2JUJh", "_score": 1, "_source": { "name": "Fahrenheit 451", "author": "Ray Bradbury", "release_date": "1953-10-15", "page_count": 227 } }, { "_index": "kibana_sample_data_basics", "_id": "ETElB5sBcDVt1ED2JUJh", "_score": 1, "_source": { "name": "Brave New World", "author": "Aldous Huxley", "release_date": "1932-06-01", "page_count": 268 } }, { "_index": "kibana_sample_data_basics", "_id": "EjElB5sBcDVt1ED2JUJh", "_score": 1, "_source": { "name": "The Handmaids Tale", "author": "Margaret Atwood", "release_date": "1985-06-01", "page_count": 311 } }, { "_index": "kibana_sample_data_basics", "_id": "EzEpB5sBcDVt1ED2o0Ky", "_score": 1, "_source": { "name": "The Great Gatsby", "author": "F. Scott Fitzgerald", "release_date": "1925-04-10", "page_count": 180, "language": "EN" } } ] } } ``` #### 8、匹配查询文档 搜索在特定字段中包含特定值的文档 ##### 带条件搜索 ```bash curl -X GET "localhost:9200/kibana_sample_data_basics/_search?pretty" -H 'Content-Type: application/json' -d' { "query": { "match": { "name": "brave" } } } ' ``` ##### 通过ID搜索 ```bash curl -X GET "localhost:9200/kibana_sample_data_basics/_doc/ETElB5sBcDVt1ED2JUJh?pretty" ``` ##### 跨索引搜索 通过通配符`*`进行跨索引搜索 ```bash curl -X GET "localhost:9200/kibana_sample_data_basics*/_search" -H 'Content-Type: application/json' -d' { "query": { "match": { "author": "Aldous Huxley" } } } ' ``` ##### 返回示例 响应包含与搜索词 `brave` 匹配的文档列表 ```bash { "took": 1, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 1, "relation": "eq" }, "max_score": 1.484231, "hits": [ { "_index": "kibana_sample_data_basics", "_id": "ETElB5sBcDVt1ED2JUJh", "_score": 1.484231, "_source": { "name": "Brave New World", "author": "Aldous Huxley", "release_date": "1932-06-01", "page_count": 268 } } ] } } ``` #### 9、删除索引 **删除索引将`永久`删除其文档、分片和元数据。** ```bash curl -X DELETE "localhost:9200/kibana_sample_data_basics" ``` ##### 返回示例 响应包含索引已被删除的确认信息 ```bash { "acknowledged": true } ``` ## 三、SpringBoot使用ES #### 1、修改ES设置 打开安装目录下`config/elasticsearch.yml`,将`xpack.security.enabled`改为`false`,否则会拒绝HTTP请求  #### 2、添加起步依赖 将`Spring Data Elasticsearch`加入起步依赖 <img src="https://pic.soki.me/file/piclist/image-20251211185136862-1765450297298.png" alt="image-20251211185136862" style="zoom:67%;" style=""> #### 3、修改配置 在配置文件中添加 ```yml spring: # Elasticsearch 配置 elasticsearch: uris: http://localhost:9200 # 如果有用户名密码,可以配置 username: elastic password: Hwk_TlPR+yT=XNb6BbZR ``` 或者`properties`配置 ```properties # Elasticsearch 配置 spring.elasticsearch.uris=http://localhost:9200 # 如果有用户名密码,可以配置 spring.elasticsearch.username=elastic spring.elasticsearch.password=Hwk_TlPR+yT=XNb6BbZR ``` #### 4、创建文档实体类 使用`@Document`注解映射 Elasticsearch 索引,当索引不存在时会自动创建索引 以`Product`为例,创建`po/Product.java` ```java import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.data.annotation.Id; import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.Field; import org.springframework.data.elasticsearch.annotations.FieldType; @Data @NoArgsConstructor @AllArgsConstructor @Document(indexName = "product") // 指定索引名称 public class Product { @Id // 主键 private String id; @Field(type = FieldType.Text, analyzer = "ik_max_word") // 文本类型,使用 IK 分词器 private String name; @Field(type = FieldType.Keyword) // 关键字类型,不分词 private String category; @Field(type = FieldType.Double) // 数字类型 private Double price; @Field(type = FieldType.Integer) private Integer stock; @Field(type = FieldType.Text, analyzer = "ik_max_word") private String description; } ``` #### 5、创建DAO 创建`dao/ProductRepository.java`,继承 `ElasticsearchRepository`,自动实现基础 CRUD 操作 ```java import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; import org.springframework.stereotype.Repository; import java.util.List; @Repository public interface ProductRepository extends ElasticsearchRepository<Product, String> { // Spring Data Elasticsearch 支持方法名查询 List<Product> findByName(String name); List<Product> findByCategory(String category); List<Product> findByPriceBetween(Double minPrice, Double maxPrice); List<Product> findByNameContaining(String keyword); } ``` #### 6、创建Service 创建`service/ProductService.java`接口 ```java import cn.doooog.esdome.po.Product; import org.springframework.data.domain.Page; import java.util.List; import java.util.Optional; public interface ProductService { Product save(Product product); Iterable<Product> saveAll(List<Product> products); Optional<Product> findById(String id); Iterable<Product> findAll(); Page<Product> findAll(int page, int size); List<Product> findByName(String name); List<Product> findByCategory(String category); List<Product> findByPriceRange(Double minPrice, Double maxPrice); List<Product> searchByKeyword(String keyword); void deleteById(String id); void deleteAll(); } ``` 创建`service/impl/ProductServiceImpl.java` ```java import cn.doooog.esdome.dao.ProductRepository; import cn.doooog.esdome.po.Product; import cn.doooog.esdome.service.ProductService; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; import java.util.List; import java.util.Optional; /** * Product Service */ @Service @RequiredArgsConstructor public class ProductServiceImpl implements ProductService { private final ProductRepository productRepository; /** * 保存商品 */ public Product save(Product product) { return productRepository.save(product); } /** * 批量保存商品 */ public Iterable<Product> saveAll(List<Product> products) { return productRepository.saveAll(products); } /** * 根据 ID 查询商品 */ public Optional<Product> findById(String id) { return productRepository.findById(id); } /** * 查询所有商品 */ public Iterable<Product> findAll() { return productRepository.findAll(); } /** * 分页查询 */ public Page<Product> findAll(int page, int size) { return productRepository.findAll(PageRequest.of(page, size)); } /** * 根据名称查询 */ public List<Product> findByName(String name) { return productRepository.findByName(name); } /** * 根据类别查询 */ public List<Product> findByCategory(String category) { return productRepository.findByCategory(category); } /** * 根据价格区间查询 */ public List<Product> findByPriceRange(Double minPrice, Double maxPrice) { return productRepository.findByPriceBetween(minPrice, maxPrice); } /** * 根据关键字模糊查询 */ public List<Product> searchByKeyword(String keyword) { return productRepository.findByNameContaining(keyword); } /** * 根据 ID 删除 */ public void deleteById(String id) { productRepository.deleteById(id); } /** * 删除所有 */ public void deleteAll() { productRepository.deleteAll(); } } ``` #### 7、创建Controller 创建`controller/ProductController.java` ```java import cn.doooog.esdome.po.Product; import cn.doooog.esdome.service.ProductService; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @RequestMapping("/api/products") @RequiredArgsConstructor public class ProductController { private final ProductService productService; /** * 添加商品 */ @PostMapping public ResponseEntity<Product> addProduct(@RequestBody Product product) { Product saved = productService.save(product); return ResponseEntity.ok(saved); } /** * 批量添加商品 */ @PostMapping("/batch") public ResponseEntity<Iterable<Product>> addProducts(@RequestBody List<Product> products) { Iterable<Product> saved = productService.saveAll(products); return ResponseEntity.ok(saved); } /** * 根据 ID 查询商品 */ @GetMapping("/{id}") public ResponseEntity<Product> getProduct(@PathVariable String id) { return productService.findById(id) .map(ResponseEntity::ok) .orElse(ResponseEntity.notFound().build()); } /** * 查询所有商品 */ @GetMapping public ResponseEntity<Iterable<Product>> getAllProducts() { return ResponseEntity.ok(productService.findAll()); } /** * 分页查询商品 */ @GetMapping("/page") public ResponseEntity<Page<Product>> getProductsPage( @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "10") int size) { return ResponseEntity.ok(productService.findAll(page, size)); } /** * 根据名称查询商品 */ @GetMapping("/search/name") public ResponseEntity<List<Product>> searchByName(@RequestParam String name) { return ResponseEntity.ok(productService.findByName(name)); } /** * 根据类别查询商品 */ @GetMapping("/search/category") public ResponseEntity<List<Product>> searchByCategory(@RequestParam String category) { return ResponseEntity.ok(productService.findByCategory(category)); } /** * 根据价格区间查询商品 */ @GetMapping("/search/price") public ResponseEntity<List<Product>> searchByPrice( @RequestParam Double minPrice, @RequestParam Double maxPrice) { return ResponseEntity.ok(productService.findByPriceRange(minPrice, maxPrice)); } /** * 关键字模糊搜索 */ @GetMapping("/search") public ResponseEntity<List<Product>> search(@RequestParam String keyword) { return ResponseEntity.ok(productService.searchByKeyword(keyword)); } /** * 更新商品 */ @PutMapping("/{id}") public ResponseEntity<Product> updateProduct( @PathVariable String id, @RequestBody Product product) { product.setId(id); Product updated = productService.save(product); return ResponseEntity.ok(updated); } /** * 删除商品 */ @DeleteMapping("/{id}") public ResponseEntity<Void> deleteProduct(@PathVariable String id) { productService.deleteById(id); return ResponseEntity.noContent().build(); } /** * 删除所有商品 */ @DeleteMapping public ResponseEntity<Void> deleteAllProducts() { productService.deleteAll(); return ResponseEntity.noContent().build(); } } ``` 最后修改:2025 年 12 月 11 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 👆请简单粗暴地爱我。