文章部分代码参考博文
https://www.cnblogs.com/ifme/p/12005026.html
1 pom.xml文件配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.essearch</groupId>
<artifactId>study_1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>study_1</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2 application.yaml文件配置
spring:
data:
elasticsearch:
cluster-name: elasticsearch
cluster-nodes: localhost:9300
3 实体类和注解配置
Spring Data通过注解来声明字段的映射属性,有下面的三个注解:
@Document
作用在类,标记实体类为文档对象,一般有四个属性- indexName:对应索引库名称
- type:对应在索引库中的类型 (高版本的已经去掉些属性)
- shards:分片数量,默认5
- replicas:副本数量,默认1
@Id
作用在成员变量,标记一个字段作为id主键@Field
作用在成员变量,标记为文档的字段,并指定字段映射属性:- type:字段类型,取值是枚举:FieldType
- index:是否索引,布尔类型,默认是true
- store:是否存储,布尔类型,默认是false
- analyzer:分词器名称:ik_max_word
Item实体类和注解的设置
package com.essearch.study_1.pojo;
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;
/**
* @author john
* @date 2019/12/8 - 13:47
*/
//注意:有些低版本的ES,这里有个type设置,高版本的已经去掉了,系统内部直接设置为_doc
@Document(indexName = "item", shards = 1, replicas = 0)
public class Item {
@Id
private Long id;
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String title; //标题
@Field(type = FieldType.Keyword)
private String category;// 分类
@Field(type = FieldType.Keyword)
private String brand; // 品牌
@Field(type = FieldType.Double)
private Double price; // 价格
@Field(index = false, type = FieldType.Keyword)
private String images; // 图片地址
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String getImages() {
return images;
}
public void setImages(String images) {
this.images = images;
}
public Item(Long id, String title, String category, String brand, Double price, String images) {
this.id = id;
this.title = title;
this.category = category;
this.brand = brand;
this.price = price;
this.images = images;
}
public Item() {
}
@Override
public String toString() {
return "Item{" +
"id=" + id +
", title='" + title + '\'' +
", category='" + category + '\'' +
", brand='" + brand + '\'' +
", price=" + price +
", images='" + images + '\'' +
'}';
}
}
Spring Data 的强大之处,就在于你不用写任何DAO处理,自动根据方法名或类的信息进行CRUD操作。只要你定义一个接口,然后继承Repository提供的一些子接口,就能具备各种基本的CRUD功能。
4 编写一个接口,继承 ElasticsearchRepository
package com.essearch.study_1.dao;
import com.essearch.study_1.pojo.Item;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface ItemRepository extends ElasticsearchRepository<Item,Long> {
//这个一个自定义的方法,不需要写实现类,spring Data Es底层会自动根据名称来实现
/**
* 根据价格区间查询
* @param price1
* @param price2
* @return
*/
List<Item> findByPriceBetween(double price1, double price2);
}
5 创建索引,增删改查等操作
注意search的两个用法
itemRepository.search(QueryBuilders.各种查询类型)
itemRepository.search(NativeSearchQueryBuilder)
QueryBuilders提供了大量的静态方法,用于生成各种不同类型的查询对象,例如:词条、模糊、通配符等QueryBuilder对象。不可以分页,排序
NativeSearchQueryBuilder:Spring提供的一个查询条件构建器,帮助构建json格式的请求体,可实现分页,排序等 ,并可以调用上面的 QueryBuilders 类
Page<item>
:默认是分页查询,因此返回的是一个分页的结果对象,包含属性:
- totalElements:总条数
- totalPages:总页数
- Iterator:迭代器,本身实现了Iterator接口,因此可直接迭代得到当前页的数据
- 其它属性:
package com.essearch.study_1;
import com.essearch.study_1.dao.ItemRepository;
import com.essearch.study_1.pojo.Item;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
@SpringBootTest
@RunWith(SpringRunner.class)
class Study1ApplicationTests {
@Autowired
private org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate elasticsearchRestTemplate;
@Autowired
private ItemRepository itemRepository;
//创建索引库和配置映射
@Test
void fangfa_1() {
/**
* 创建索引,会根据Item类的@Document注解信息来创建
* 注意:这里要注释,因为下面的代码会自动创建索引库和添加mapping,否则会报错
*/
//elasticsearchRestTemplate.createIndex(Item.class);
// 配置映射,会根据Item类中的id、Field等字段来自动完成映射
elasticsearchRestTemplate.putMapping(Item.class);
}
//添加文档
@Test
void fangfa_2() {
Item item = new Item(1L, "小米手机7", " 手机",
"小米", 3499.00, "http://image.leyou.com/13123.jpg");
itemRepository.save(item);
}
//id存在就是修改,否则就是插入
@Test
void fangfa_3() {
Item item = new Item(1L, "小米手机7.1", " 手机",
"小米", 3499.00, "http://image.leyou.com/13123.jpg");
itemRepository.save(item);
Item item_2 = new Item(2L, "华为手机p40", " 手机",
"华为", 6599.00, "http://image.leyou.com/13125.jpg");
itemRepository.save(item_2);
}
//批量新增
@Test
void fangfa_4() {
ArrayList<Item> items = new ArrayList<>();
items.add(new Item(4L, "华为手机p40-6g-64", " 手机",
"华为", 31.00, "http://image.leyou.com/13185.jpg"));
items.add(new Item(5L, "华为手机p40-12g-64", " 手机",
"华为", 55.00, "http://image.leyou.com/13188.jpg"));
items.add(new Item(6L, "华为手机p40-12g-128", " 手机",
"华为", 9.00, "http://image.leyou.com/13190.jpg"));
items.add(new Item(7L, "小米手机7", "手机", "小米", 3299.00, "http://image.leyou.com/13123.jpg"));
items.add(new Item(8L, "坚果手机R1", "手机", "锤子", 3699.00, "http://image.leyou.com/13123.jpg"));
items.add(new Item(9L, "华为META10", "手机", "华为", 4499.00, "http://image.leyou.com/13123.jpg"));
items.add(new Item(10L, "小米Mix2S", "手机", "小米", 4299.00, "http://image.leyou.com/13123.jpg"));
items.add(new Item(11L, "荣耀V10", "手机", "华为", 2799.00, "http://image.leyou.com/13123.jpg"));
itemRepository.saveAll(items);
}
//删除
@Test
void fangfa_5() {
itemRepository.deleteById(1L);
}
//根据id查询
@Test
void fangfa_6() {
Optional<Item> byId = itemRepository.findById(2L);
System.out.println(byId.get().toString());
}
//查询全部,并排序
@Test
void fangfa_7() {
Iterable<Item> id = itemRepository.findAll(Sort.by("id").descending());
Iterator<Item> iterator = id.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
System.out.println("--------------");
Iterable<Item> price = itemRepository.findAll(Sort.by(Sort.Direction.ASC, "price"));
price.forEach(aa -> System.out.println(aa));
}
//自定义方法,无需写实现类。
@Test
void fangfa_7_1() {
List<Item> itemList = itemRepository.findByPriceBetween(20.0, 60.0);
itemList.forEach(new Consumer<Item>() {
@Override
public void accept(Item item) {
System.out.println(item);
}
});
}
//----------------------------------以下部分是高级查询------------------------------------------
@Test
void fangfa_8() {
//针对keyword类型的查找
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("brand", "小米");
Iterable<Item> search_List_1 = itemRepository.search(termQueryBuilder);
search_List_1.forEach(new Consumer<Item>() {
@Override
public void accept(Item item) {
System.out.println(item);
}
});
System.out.println("------------------------");
//会对text类型的查找,会分词
//多个字段 查找
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("华为", "title", "brand");
//单个字段 查找
MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title", "坚果");
Iterable<Item> search_List_2 = itemRepository.search(matchQueryBuilder);
search_List_2.forEach(new Consumer<Item>() {
@Override
public void accept(Item item) {
System.out.println(item);
}
});
System.out.println("------------------------");
//范围查找
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("price").from(9.00).to(55.00);
Iterable<Item> search_List_3 = itemRepository.search(rangeQueryBuilder);
search_List_3.forEach(new Consumer<Item>() {
@Override
public void accept(Item item) {
System.out.println(item);
}
});
System.out.println("------------------------");
//前缀查询
PrefixQueryBuilder prefixQueryBuilder = QueryBuilders.prefixQuery("title", "华为");
Iterable<Item> search_List_4 = itemRepository.search(prefixQueryBuilder);
search_List_4.forEach(new Consumer<Item>() {
@Override
public void accept(Item item) {
System.out.println(item);
}
});
}
//自定义基本查询
@Test
void fangfa_9() {
// 构建查询条件
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
// 添加基本的分词查询
nativeSearchQueryBuilder.withQuery(QueryBuilders.matchQuery("title", "华为"));
// 执行搜索,获取结果
Page<Item> itemList_1 = itemRepository.search(nativeSearchQueryBuilder.build());
// 打印总条数
long totalElements = itemList_1.getTotalElements();
System.out.println(totalElements);
// 打印总页数
int totalPages = itemList_1.getTotalPages();
System.out.println(totalPages);
itemList_1.forEach(new Consumer<Item>() {
@Override
public void accept(Item item) {
System.out.println(item);
}
});
}
//自定义基本查询 + 分页
@Test
void fangfa_10() {
// 构建查询条件
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
// 添加基本的分词查询
nativeSearchQueryBuilder.withQuery(QueryBuilders.matchQuery("title", "华为"));
// 初始化分页参数
// 可以发现,Elasticsearch中的分页是从第0页开始
Integer page = 1;
Integer pageSize = 3;
// 设置分页参数
nativeSearchQueryBuilder.withPageable(PageRequest.of(page, pageSize));
// 执行搜索,获取结果
Page<Item> itemList_1 = itemRepository.search(nativeSearchQueryBuilder.build());
// 打印总条数
long totalElements = itemList_1.getTotalElements();
System.out.println("总条数:" + totalElements);
// 打印总页数
int totalPages = itemList_1.getTotalPages();
System.out.println("总页数:" + totalPages);
//每页大小
System.out.println("每页数:" + itemList_1.getSize());
//当前页
System.out.println("当前页:" + itemList_1.getNumber());
itemList_1.forEach(new Consumer<Item>() {
@Override
public void accept(Item item) {
System.out.println(item);
}
});
}
//自定义基本查询 + 排序
@Test
void fangfa_11() {
// 构建查询条件
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
// 添加基本的分词查询
nativeSearchQueryBuilder.withQuery(QueryBuilders.matchQuery("title", "华为"));
// 设置排序
nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC));
Page<Item> itemList_1 = itemRepository.search(nativeSearchQueryBuilder.build());
// 打印总条数
long totalElements = itemList_1.getTotalElements();
System.out.println("总条数:" + totalElements);
// 打印总页数
int totalPages = itemList_1.getTotalPages();
System.out.println("总页数:" + totalPages);
//每页大小
System.out.println("每页数:" + itemList_1.getSize());
//当前页
System.out.println("当前页:" + itemList_1.getNumber());
itemList_1.forEach(new Consumer<Item>() {
@Override
public void accept(Item item) {
System.out.println(item);
}
});
}
}