新建测试 bean:
// zze.springboot.elasticsearch.bean.Product
import io.searchbox.annotations.JestId;
public class Product {
private Integer id;
private String name;
private String remark;
private Double price;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "Product{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
SpringBoot 默认支持两种以下两种方式操作 Elasticsearch。
Jest 操作
1、使用 Maven 新建 SpringBoot 项目,引入 Web 场景启动器,导入 Jest 的依赖:
<dependency>
<groupId>io.searchbox</groupId>
<artifactId>jest</artifactId>
<version>5.3.4</version>
</dependency>
2、配置 Elasticsearch 服务主机地址,使用 9200 端口:
# application.properties
spring.elasticsearch.jest.uris=http://192.168.202.136:9200
3、修改文档 bean,使用注解标识主键:
// zze.springboot.elasticsearch.bean.Product
import io.searchbox.annotations.JestId;
public class Product {
@JestId
private Integer id;
private String name;
private String remark;
private Double price;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "Product{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
4、测试:
import io.searchbox.client.JestClient;
import io.searchbox.core.Index;
import io.searchbox.core.Search;
import io.searchbox.core.SearchResult;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import zze.springboot.elasticsearch.bean.Product;
import java.io.IOException;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class JestTests {
@Autowired
private JestClient jestClient;
// 索引文档
@Test
public void testIndex() {
// 创建一个产品作为文档
Product product = new Product();
product.setId(1);
product.setName("iphone 8 plus");
product.setPrice(5300D);
product.setRemark("刺激战场首选");
// 构建一个 product 索引,索引文档到该索引下 phone 类型
Index index = new Index.Builder(product).index("product").type("phone").build();
try {
jestClient.execute(index);
} catch (IOException e) {
e.printStackTrace();
}
}
// 搜索
@Test
public void testSearch() {
// 查询表达式
String json = "{\n" +
" \"query\": {\n" +
" \"match\": {\n" +
" \"name\": \"iphone 8 plus\"\n" +
" }\n" +
" }\n" +
"}"; // 空字符串为查询所有
// 构建搜索对象,指定在 product 索引的 phone 类型下通过 json 变量指定的查询表达式搜索
Search search = new Search.Builder(json).addIndex("product").addType("phone").build();
try {
SearchResult searchResult = jestClient.execute(search);
List<SearchResult.Hit<Product, Void>> hits = searchResult.getHits(Product.class);
for (SearchResult.Hit<Product, Void> hit : hits) {
System.out.println(hit.source);
}
} catch (IOException e) {
e.printStackTrace();
}
/*
Product{id=1, name='iphone 8 plus'}
*/
}
}
SpringData操作
SpringBoot 默认使用 SpringData 来操作 Elasticsearch。
Spring Data Elasticsearch 官方文档 | Spring Data Elasticsearch GitHub
1、使用 maven 新建 SpringBoot 项目,引入 Web、Elasticsearch 场景启动器。
2、配置 Elasticsearch 服务主机地址,使用 9300 端口:
# application.properties
spring.data.elasticsearch.cluster-name=elasticsearch
spring.data.elasticsearch.cluster-nodes=192.168.202.136:9300
3、修改文档 bean,使用注解指定文档存放的索引及类型:
// zze.springboot.elasticsearch.bean.Product
import org.springframework.data.elasticsearch.annotations.Document;
@Document(indexName = "product",type = "phone") // 指定该类型实例是一个文档对象,存放在 product 索引下 phone 类型中
public class Product {
private Integer id;
private String name;
private String remark;
private Double price;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "Product{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
ElasticsearchRepository 操作
1、新建 Repository
接口:
// zze.springboot.elasticsearch.repository.ProductRepository
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import zze.springboot.elasticsearch.bean.Product;
import java.util.List;
public interface ProductRepository extends ElasticsearchRepository<Product, Integer> {
// 扩展 ElasticsearchRepository 自定义方法,使用可参考官方文档及 GitHub 文档
public List<Product> findProductByNameLike(String name);
}
2、测试:
import io.searchbox.client.JestClient;
import io.searchbox.core.Index;
import io.searchbox.core.Search;
import io.searchbox.core.SearchResult;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import zze.springboot.elasticsearch.bean.Product;
import zze.springboot.elasticsearch.repository.ProductRepository;
import java.io.IOException;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ElasticsearchRepositoryTests {
@Autowired
private ProductRepository productRepository;
// 索引文档
@Test
public void testIndex() {
// 创建一个产品作为文档
Product product = new Product();
product.setId(1);
product.setName("iphone 8 plus");
product.setPrice(5300D);
product.setRemark("刺激战场首选");
productRepository.index(product);
}
// 搜索
@Test
public void testSearch() {
Iterable<Product> products = productRepository.findAll();
products.forEach(p-> System.out.println(p));
/*
Product{id=1, name='iphone 8 plus'}
*/
}
// 根据名称查询
@Test
public void testFindByName(){
// like 模糊查询时值不能直接使用空格,需要使用 \b 转义
List<Product> products = productRepository.findProductByNameLike("iphone\b8");
products.fotestrEach(p-> System.out.println(p));
/*
Product{id=1, name='iphone 8 plus'}
*/
}
}
关于在接口中扩展查询方法可参考如下范例:
关键字 | 例子 | 对应查询表达式 |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
不仅如此,还可以通过注解让指定查询表达式绑定到扩展的查询方法,如:
@Query("{\"bool\" : {\"must\" : {\"field\" : {\"name\" : \" ? 0\"}}}}")
Page<Product> findByName(String name, Pageable pageable);
更多使用细节参考官方文档 2.2 节。
ElasticsearchTemplate 操作
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.test.context.junit4.SpringRunner;
import zze.springboot.elasticsearch.bean.Product;
import zze.springboot.elasticsearch.repository.ProductRepository;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ElasticsearchTemplateTests {
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
// 索引文档
@Test
public void testIndex() {
// 创建一个产品作为文档
Product product = new Product();
product.setId(3);
product.setName("iphone 9 plus");
product.setPrice(5300D);
product.setRemark("刺激战场首选");
IndexQuery indexQuery = new IndexQueryBuilder().withIndexName("product")
.withType("phone").withId(product.getId().toString()).withObject(product).build();
elasticsearchTemplate.index(indexQuery);
}
// 搜索
@Test
public void testSearch() {
// 构建查询构建器
BoolQueryBuilder bqb = QueryBuilders.boolQuery();
bqb.must(QueryBuilders.boolQuery()
.should(QueryBuilders.matchQuery("id","3")));
// 构建一个搜索查询
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(bqb).withIndices("product").withTypes("phone")
.withSearchType(SearchType.DEFAULT)
.build();
List<Product> products = elasticsearchTemplate.queryForList(searchQuery, Product.class);
for (Product product : products) {
System.out.println(product);
}
/*
Product{id=3, name='iphone 9 plus'}
*/
}
}
注意:SpringData 依赖的 Elasticsearch 依赖版本需要与 Elasticsearch 服务器版本匹配,在 GitHub 中有说明规则:
spring data elasticsearch | elasticsearch |
---|---|
3.2.x | 6.5.0 |
3.1.x | 6.2.2 |
3.0.x | 5.5.0 |
2.1.x | 2.4.0 |
2.0.x | 2.2.0 |
1.3.x | 1.5.2 |
如果版本不匹配,会抛出如下异常:
org.elasticsearch.transport.ConnectTransportException: [][192.168.202.136:9300/192.168.202.136:9300
解决方案是修改依赖版本或者重新安装 Elasticsearch 指定版本服务。
评论区