前言
Elasticsearch是开源的分布式搜索服务,提供Restful API,底层是基于lucene,采用多shard(分片)方式保证数据安全,提供了自动resharding功能,添加检索功能,是目前全文搜索引擎的首选,它可以快速存储,搜索和分析海量数据,GitHub等大性站点采用的也是Elasticsearch作为其搜索服务。
Spring Data Elasticsearch项目将Spring的核心概念应用于使用Elasticsearch Search Engine的解决方案的开发中。 它提供:
模板 是用于存储,搜索,排序文档和构建聚合的高级抽象
。
存储库 例如, 使用户能够通过定义具有自定义方法名称的接口来表达查询
您会注意到与Spring框架中的Spring数据solr和mongodb支持相似。
直接上代码:
这里我是用的是ElasticSearch:7.12.0版+springboot:2.4.5版
1.导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
2.创建客户端配置类: 这里我用的是RestHighLevelClient基于http的
/**
* ElasticSearch 客户端配置
* @author yang
*/
@Configuration
public class RestClientConfig extends AbstractElasticsearchConfiguration {
@Override
@Bean
public RestHighLevelClient elasticsearchClient() {
final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo("ES安装机器的ip:9200")
.build();
return RestClients.create(clientConfiguration).rest();
}
}
3.创建实体类:
/**
* createIndex = true 无需手动创建Book索引,Springboot启动自动创建
* @Document 作用在类,标记实体类为文档对象,一般有四个属性
* indexName:对应索引库名称
* shards:分片数量,默认5
* replicas:副本数量,默认1
* @Id 作用在成员变量,标记一个字段作为id主键
* @Field 作用在成员变量,标记为文档的字段,并指定字段映射属性:
* type:字段类型,取值是枚举:FieldType
* index:是否索引,布尔类型,默认是true
* store:是否存储,布尔类型,默认是false
* analyzer:分词器名称:ik_max_word
* @Transient 默认情况下,存储或检索文档时,所有字段都映射到文档,此注释不包括该字段。
*/
@Document(indexName = "book",createIndex = true)
public class Book {
@Id
@Field(type = FieldType.Text)
private String id;
@Field(analyzer="ik_max_word")
private String title;
@Field(analyzer="ik_max_word")
private String author;
@Field(type = FieldType.Double)
private Double price;
@Field(type = FieldType.Date,format = DateFormat.basic_date_time)
private Date createTime;
@Field(type = FieldType.Date,format = DateFormat.basic_date_time)
private Date updateTime;
public Book() {
}
public Book(String id, String title, String author, Double price, Date createTime, Date updateTime) {
this.id = id;
this.title = title;
this.author = author;
this.price = price;
this.createTime = createTime;
this.updateTime = updateTime;
}
//省略set/get方法/toString方法
}
4.创建Repository仓库:
/**
* ES Book repository
*
* @author yang
*/
public interface ESBookRepository extends ElasticsearchRepository<Book, String> {
List<Book> findByTitleOrAuthor(String title, String author);
@Highlight(fields = {
@HighlightField(name = "title"),
@HighlightField(name = "author")
})
@Query("{\"match\":{\"title\":\"?0\"}}")
SearchHits<Book> find(String keyword);
}
5.测试类测试结果:
@SpringBootTest
class Springboot213Elasticsearch2ApplicationTests {
@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;
@Autowired
private ESBookRepository esBookRepository;
/**
* 创建索引
*/
@Test
public void testCreateIndex(){
IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Book.class);
Document mapping = indexOperations.createMapping();
indexOperations.putMapping(mapping);
}
/**
* 删除索引
*/
@Test
public void testDeleteIndex() {
IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Book.class);
indexOperations.delete();
}
/**
* 新增/修改文档
*/
@Test
void test01() {
Book book = new Book("123", "内容体", "yang", 500.0, null, null);
elasticsearchRestTemplate.save(book);
}
/**
* 删除文档
*/
@Test
void test02() {
esBookRepository.deleteById("123");
}
/**
* 查询文档
*/
@Test
void test30() { //普通查询 按price排序查询
Iterable<Book> book =
esBookRepository.findAll(Sort.by("price").descending());
book.forEach(System.out::println);
}
@Test
void test31() { //自定义查询
List<Book> book =
esBookRepository.findByTitleOrAuthor("内容体", "yang");
book.forEach(System.out::println);
}
@Test
void test32() { //自定义json规则查询
SearchHits<Book> book = esBookRepository.find("内容体");
book.forEach(System.out::println);
}
}
部分结果:
补充:
- 高级查询:
public void testSearch() {
//创建NativeSearchQueryBuilder对象
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
//构建全文检索条件
queryBuilder.withQuery(QueryBuilders.matchQuery("xxx", "xxx"));
//构建分页查询条件
queryBuilder.withPageable(PageRequest.of(0, 1));
//排序查询添加
builder.withSort(SortBuilders.fieldSort(xxx).order(SortOrder.ASC));
//获得查询结果对象
SearchHits<Book> hits = elasticsearchRestTemplate.search(queryBuilder.build(), Book.class);
//取出查询的数据
List<Book> books = hits.stream().map(SearchHit::getContent).collect(Collectors.toList());
books.forEach(System.out::println);
}
- 聚合查询
public void testAgg() {
// 初始化自定义查询构建器
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// 添加聚合,嵌套聚合求平均值
queryBuilder.addAggregation(AggregationBuilders.terms("新字段名").field("字段名")
.subAggregation(AggregationBuilders.avg("新字段名").field("字段名")));
// 执行聚合查询,获取分组数据
SearchHits<Book> searchHits = elasticsearchRestTemplate.search(queryBuilder.build(), Book.class);
//转换对象
Terms terms = (Terms) searchHits.getAggregations().asMap().get("xxx");
//获得聚合后的桶
List<? extends Terms.Bucket> buckets = terms.getBuckets();
}