2026/1/28 6:43:32
网站建设
项目流程
网站建设 需要准备材料,wordpress vip查看插件,免费的个人的网站,公益 建网站大家好#xff0c;我是小悟。
一、ElasticSearch 是什么#xff1f;
你有一个超级健忘的朋友#xff08;比如金鱼记忆的那种#xff09;#xff0c;但他却能在0.0001秒内从100万本书里找到你想要的句子。这就是 ElasticSearch#xff08;简称 ES#xff09;#xff01;…大家好我是小悟。一、ElasticSearch 是什么你有一个超级健忘的朋友比如金鱼记忆的那种但他却能在0.0001秒内从100万本书里找到你想要的句子。这就是 ElasticSearch简称 ESES 的“人格特征”速度狂魔搜索速度比咖啡因过量的程序员找Bug还快文档收藏家什么JSON、日志都能存超级侦探模糊搜索、精确搜索、拼音搜索样样精通大象胃口数据量再大也不怕毕竟名字里就有“elastic”弹性马戏团团长天生分布式节点之间跳来跳去从不出错二、整合大冒险SpringBoot 与 ES 的“相亲大会”第 1 步先来个“相亲介绍人”Maven 依赖!-- pom.xml 里加入这些“红娘” -- dependencies !-- SpringBoot 给 ES 的专属“情书” -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-elasticsearch/artifactId /dependency !-- 防止程序说“我不会JSON” -- dependency groupIdcom.fasterxml.jackson.core/groupId artifactIdjackson-databind/artifactId /dependency /dependencies第 2 步配置“约会地点”application.yml# application.yml spring: elasticsearch: uris: http://localhost:9200 # ES 的“家庭地址” username: elastic # 用户名默认是这个 password: your_password # 密码安装时设置的 # 可选让日志“多说点话”方便调试 data: elasticsearch: repositories: enabled: true # 给 ES 客户端一点“咖啡因”让它更精神 elasticsearch: connection-timeout: 5000 # 连接超时毫秒 socket-timeout: 30000 # socket超时第 3 步创建“相亲对象”实体类import lombok.Data; 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; import java.util.Date; import java.util.List; Data Document(indexName book_index) // 告诉ES“这是我家的书架名字” public class Book { Id // 相当于书的“身份证号” private String id; Field(type FieldType.Text, analyzer ik_max_word) // 用中文分词器 private String title; // 书名 Field(type FieldType.Text, analyzer ik_smart) private String author; // 作者 Field(type FieldType.Double) private Double price; // 价格 Field(type FieldType.Date) private Date publishDate; // 出版日期 Field(type FieldType.Keyword) // 关键词不分词 private String category; // 分类 Field(type FieldType.Nested) // 嵌套对象 private ListTag tags; Data public static class Tag { Field(type FieldType.Keyword) private String name; Field(type FieldType.Integer) private Integer priority; } }第 4 步找个“媒婆”Repository 接口import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.elasticsearch.annotations.Query; import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; import org.springframework.stereotype.Repository; import java.util.List; Repository public interface BookRepository extends ElasticsearchRepositoryBook, String { // 方法名就是查询Spring Data 的“魔法” // 1. 按作者精确查找比找失散多年的兄弟还准 ListBook findByAuthor(String author); // 2. 按标题模糊查找支持分词 ListBook findByTitleContaining(String keyword); // 3. 价格区间查找找买得起的书 ListBook findByPriceBetween(Double minPrice, Double maxPrice); // 4. 多条件查询作者分类 ListBook findByAuthorAndCategory(String author, String category); // 5. 自定义查询展示真正的技术 Query({\bool\: {\must\: [{\match\: {\title\: \?0\}}]}}) PageBook customSearch(String keyword, Pageable pageable); // 6. 统计某个作者有多少书 Long countByAuthor(String author); }第 5 步写个“恋爱导师”Service 层import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import java.util.List; import java.util.Optional; Service public class BookService { Autowired private BookRepository bookRepository; /** * 添加/更新一本书 * 如果书有id就是更新没有id就是新增 */ public Book saveBook(Book book) { return bookRepository.save(book); } /** * 批量添加ES最喜欢批量操作了效率高 */ public void saveAllBooks(ListBook books) { bookRepository.saveAll(books); } /** * 按ID查找速度飞快 */ public OptionalBook findById(String id) { return bookRepository.findById(id); } /** * 复杂搜索按标题和作者搜索 */ public ListBook searchBooks(String title, String author) { // 这里可以写更复杂的逻辑 if (title ! null author ! null) { return bookRepository.findByTitleContainingAndAuthor(title, author); } else if (title ! null) { return bookRepository.findByTitleContaining(title); } else { return bookRepository.findByAuthor(author); } } /** * 删除一本书谨慎操作 */ public void deleteBook(String id) { bookRepository.deleteById(id); } /** * 分页查询大数据量的好朋友 */ public PageBook findAllBooks(Pageable pageable) { return bookRepository.findAll(pageable); } /** * 高级搜索使用QueryBuilder */ public ListBook advancedSearch(String keyword, Double minPrice, Double maxPrice) { // 使用NativeSearchQueryBuilder构建复杂查询 // 这里先省略下面会有详细示例 return null; } }第 6 步高级搜索的“秘密武器”import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; import org.springframework.data.elasticsearch.core.SearchHits; import org.springframework.data.elasticsearch.core.query.NativeSearchQuery; import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; import org.springframework.stereotype.Service; import java.util.List; import java.util.stream.Collectors; Service public class AdvancedSearchService { Autowired private ElasticsearchRestTemplate elasticsearchRestTemplate; /** * 多条件组合搜索布尔查询 */ public ListBook multiConditionSearch(String keyword, Double minPrice, Double maxPrice, String category) { // 1. 创建布尔查询构建器相当于SQL的WHERE BoolQueryBuilder boolQuery QueryBuilders.boolQuery(); // 2. 添加必须条件must AND if (keyword ! null !keyword.trim().isEmpty()) { boolQuery.must(QueryBuilders.multiMatchQuery(keyword, title, author) .analyzer(ik_max_word)); } // 3. 添加价格范围range查询 if (minPrice ! null || maxPrice ! null) { var rangeQuery QueryBuilders.rangeQuery(price); if (minPrice ! null) { rangeQuery.gte(minPrice); } if (maxPrice ! null) { rangeQuery.lte(maxPrice); } boolQuery.must(rangeQuery); } // 4. 添加分类过滤filter不计算分数更快 if (category ! null !category.trim().isEmpty()) { boolQuery.filter(QueryBuilders.termQuery(category, category)); } // 5. 构建查询 NativeSearchQuery searchQuery new NativeSearchQueryBuilder() .withQuery(boolQuery) .withSorts(org.springframework.data.elasticsearch.core.query.SortBuilders .fieldSort(price).order(org.springframework.data.domain.Sort.Direction.ASC)) .withPageable(org.springframework.data.domain.PageRequest.of(0, 10)) .build(); // 6. 执行查询 SearchHitsBook searchHits elasticsearchRestTemplate.search(searchQuery, Book.class); // 7. 转换结果 return searchHits.getSearchHits().stream() .map(hit - hit.getContent()) .collect(Collectors.toList()); } /** * 聚合查询统计每个分类有多少本书 */ public MapString, Long categoryStatistics() { NativeSearchQuery query new NativeSearchQueryBuilder() .addAggregation(org.springframework.data.elasticsearch.core.query.aggregation.AggregationBuilders .terms(category_agg).field(category.keyword)) .build(); SearchHitsBook searchHits elasticsearchRestTemplate.search(query, Book.class); // 处理聚合结果这里简化了实际需要解析Aggregations return new HashMap(); } }第 7 步REST API 控制器对外接口import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Optional; RestController RequestMapping(/api/books) public class BookController { Autowired private BookService bookService; Autowired private AdvancedSearchService advancedSearchService; /** * 创建新书 */ PostMapping public ResponseEntityBook createBook(RequestBody Book book) { Book savedBook bookService.saveBook(book); return ResponseEntity.ok(savedBook); } /** * 批量导入适合初始化数据 */ PostMapping(/batch) public ResponseEntityString batchImport(RequestBody ListBook books) { bookService.saveAllBooks(books); return ResponseEntity.ok(成功导入 books.size() 本书); } /** * 搜索书籍简单版 */ GetMapping(/search) public ResponseEntityListBook searchBooks( RequestParam(required false) String title, RequestParam(required false) String author) { ListBook books bookService.searchBooks(title, author); return ResponseEntity.ok(books); } /** * 高级搜索多条件 */ GetMapping(/advanced-search) public ResponseEntityListBook advancedSearch( RequestParam(required false) String keyword, RequestParam(required false) Double minPrice, RequestParam(required false) Double maxPrice, RequestParam(required false) String category) { ListBook books advancedSearchService .multiConditionSearch(keyword, minPrice, maxPrice, category); return ResponseEntity.ok(books); } /** * 分页查询 */ GetMapping(/page) public ResponseEntityPageBook getBooksByPage( RequestParam(defaultValue 0) int page, RequestParam(defaultValue 10) int size) { PageBook books bookService.findAllBooks(PageRequest.of(page, size)); return ResponseEntity.ok(books); } }第 8 步配置类锦上添花import org.elasticsearch.client.RestHighLevelClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.elasticsearch.client.ClientConfiguration; import org.springframework.data.elasticsearch.client.RestClients; import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories; Configuration EnableElasticsearchRepositories(basePackages com.yourpackage.repository) public class ElasticsearchConfig { Bean public RestHighLevelClient elasticsearchClient() { ClientConfiguration clientConfiguration ClientConfiguration.builder() .connectedTo(localhost:9200) .withBasicAuth(elastic, your_password) .withConnectTimeout(5000) .withSocketTimeout(30000) .build(); return RestClients.create(clientConfiguration).rest(); } Bean public ElasticsearchRestTemplate elasticsearchRestTemplate() { return new ElasticsearchRestTemplate(elasticsearchClient()); } }三、测试一下我们的“杰作”测试数据JSON格式POST /api/books/batch [ { title: SpringBoot从入门到放弃, author: 程序猿老张, price: 68.5, category: 技术, publishDate: 2023-01-01, tags: [ {name: Java, priority: 1}, {name: 后端, priority: 2} ] }, { title: ElasticSearch实战指南, author: 搜索达人李, price: 89.0, category: 技术, publishDate: 2023-02-15, tags: [ {name: 搜索, priority: 1}, {name: 大数据, priority: 2} ] } ]搜索示例GET /api/books/search?titleSpringBootauthor程序猿老张 GET /api/books/advanced-search?keyword实战minPrice50maxPrice100四、遇到的“坑”和解决方案连接问题确保ES服务已启动检查端口9200curl http://localhost:9200版本兼容SpringBoot版本和ES版本要匹配SpringBoot 2.7.x → ES 7.17.xSpringBoot 3.x → ES 8.x中文分词安装IK分词器# 进入ES容器/安装目录的plugins文件夹 ./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.17.3/elasticsearch-analysis-ik-7.17.3.zip内存不足调整JVM参数# config/jvm.options -Xms1g -Xmx1g五、总结为什么选择这对“黄金搭档”SpringBoot ES 天作之合优点大放送开发速度SpringBoot的自动配置 ES的简单API 生产力翻倍性能表现ES的倒排索引 分布式架构 搜索如飞扩展性微服务架构中ES可作为独立的搜索服务生态完善Spring Data Elasticsearch 封装了大多数常用操作实时性近实时搜索数据一秒内可查适用场景ES大显身手的时候电商网站商品搜索、筛选、排序日志分析ELK栈中的核心组件内容平台文章、新闻的全文检索监控系统实时数据分析推荐系统用户行为分析相似度搜索最后不要滥用简单的CRUD用MySQL复杂搜索再用ES数据同步考虑使用Logstash或自定义同步机制索引设计合理的mapping设计是性能的关键监控告警用Kibana监控ES集群健康状态SpringBoot整合ElasticSearch就像给程序装上了“谷歌大脑”——存得多、找得快、查得准。虽然配置过程像在组装乐高偶尔会找不到零件版本兼容但一旦搭建完成你就能享受到“秒级搜索”的快感。谢谢你看我的文章既然看到这里了如果觉得不错随手点个赞、转发、在看三连吧感谢感谢。那我们下次再见。您的一键三连是我更新的最大动力谢谢山水有相逢来日皆可期谢谢阅读我们再会我手中的金箍棒上能通天下能探海