
大家好,我是小悟。
你有一个超级健忘的朋友(比如金鱼记忆的那种),但他却能在0.0001秒内从100万本书里找到你想要的句子。这就是 ElasticSearch(简称 ES)!
ES 的“人格特征”:
<!-- pom.xml 里加入这些“红娘” -->
<dependencies>
<!-- SpringBoot 给 ES 的专属“情书” -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<!-- 防止程序说“我不会JSON” -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies># 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超时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 List<Tag> tags;
@Data
public static class Tag {
@Field(type = FieldType.Keyword)
private String name;
@Field(type = FieldType.Integer)
private Integer priority;
}
}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 ElasticsearchRepository<Book, String> {
// 方法名就是查询!Spring Data 的“魔法”
// 1. 按作者精确查找(比找失散多年的兄弟还准)
List<Book> findByAuthor(String author);
// 2. 按标题模糊查找(支持分词)
List<Book> findByTitleContaining(String keyword);
// 3. 价格区间查找(找买得起的书)
List<Book> findByPriceBetween(Double minPrice, Double maxPrice);
// 4. 多条件查询(作者+分类)
List<Book> findByAuthorAndCategory(String author, String category);
// 5. 自定义查询(展示真正的技术)
@Query("{\"bool\": {\"must\": [{\"match\": {\"title\": \"?0\"}}]}}")
Page<Book> customSearch(String keyword, Pageable pageable);
// 6. 统计某个作者有多少书
Long countByAuthor(String author);
}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(List<Book> books) {
bookRepository.saveAll(books);
}
/**
* 按ID查找(速度飞快)
*/
public Optional<Book> findById(String id) {
return bookRepository.findById(id);
}
/**
* 复杂搜索:按标题和作者搜索
*/
public List<Book> 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 Page<Book> findAllBooks(Pageable pageable) {
return bookRepository.findAll(pageable);
}
/**
* 高级搜索:使用QueryBuilder
*/
public List<Book> advancedSearch(String keyword, Double minPrice, Double maxPrice) {
// 使用NativeSearchQueryBuilder构建复杂查询
// 这里先省略,下面会有详细示例
return null;
}
}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 List<Book> 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. 执行查询
SearchHits<Book> searchHits = elasticsearchRestTemplate.search(searchQuery, Book.class);
// 7. 转换结果
return searchHits.getSearchHits().stream()
.map(hit -> hit.getContent())
.collect(Collectors.toList());
}
/**
* 聚合查询:统计每个分类有多少本书
*/
public Map<String, Long> categoryStatistics() {
NativeSearchQuery query = new NativeSearchQueryBuilder()
.addAggregation(org.springframework.data.elasticsearch.core.query.aggregation.AggregationBuilders
.terms("category_agg").field("category.keyword"))
.build();
SearchHits<Book> searchHits = elasticsearchRestTemplate.search(query, Book.class);
// 处理聚合结果(这里简化了,实际需要解析Aggregations)
return new HashMap<>();
}
}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 ResponseEntity<Book> createBook(@RequestBody Book book) {
Book savedBook = bookService.saveBook(book);
return ResponseEntity.ok(savedBook);
}
/**
* 批量导入(适合初始化数据)
*/
@PostMapping("/batch")
public ResponseEntity<String> batchImport(@RequestBody List<Book> books) {
bookService.saveAllBooks(books);
return ResponseEntity.ok("成功导入 " + books.size() + " 本书");
}
/**
* 搜索书籍(简单版)
*/
@GetMapping("/search")
public ResponseEntity<List<Book>> searchBooks(
@RequestParam(required = false) String title,
@RequestParam(required = false) String author) {
List<Book> books = bookService.searchBooks(title, author);
return ResponseEntity.ok(books);
}
/**
* 高级搜索(多条件)
*/
@GetMapping("/advanced-search")
public ResponseEntity<List<Book>> advancedSearch(
@RequestParam(required = false) String keyword,
@RequestParam(required = false) Double minPrice,
@RequestParam(required = false) Double maxPrice,
@RequestParam(required = false) String category) {
List<Book> books = advancedSearchService
.multiConditionSearch(keyword, minPrice, maxPrice, category);
return ResponseEntity.ok(books);
}
/**
* 分页查询
*/
@GetMapping("/page")
public ResponseEntity<Page<Book>> getBooksByPage(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
Page<Book> books = bookService.findAllBooks(PageRequest.of(page, size));
return ResponseEntity.ok(books);
}
}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());
}
}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?title=SpringBoot&author=程序猿老张
GET /api/books/advanced-search?keyword=实战&minPrice=50&maxPrice=100curl http://localhost:9200# 进入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# config/jvm.options
-Xms1g
-Xmx1g优点大放送:
SpringBoot整合ElasticSearch,就像给程序装上了“谷歌大脑”——存得多、找得快、查得准。虽然配置过程像在组装乐高,偶尔会找不到零件(版本兼容),但一旦搭建完成,你就能享受到“秒级搜索”的快感。

谢谢你看我的文章,既然看到这里了,如果觉得不错,随手点个赞、转发、在看三连吧,感谢感谢。那我们,下次再见。
您的一键三连,是我更新的最大动力,谢谢
山水有相逢,来日皆可期,谢谢阅读,我们再会
我手中的金箍棒,上能通天,下能探海
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。