SpringBoot 整合 Elasticsearch
官方文档介绍
https://spring.io/projects/spring-data-elasticsearch
ElasticSearch安装版本,项目集成版本对应关系图
Spring Data Elasticsearch
Spring Data Elasticsearch是Spring提供的一种以Spring Data风格来操作数据存储的方式,它可以避免编写大量的样板代码。
常用注解
@Document 标示映射到Elasticsearch文档上的领域对象
@Persistent
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface Document {
/**
* 索引库名次,mysql中数据库的概念
* Name of the Elasticsearch index.
* <ul>
* <li>Lowercase only</li>
* <li><Cannot include \, /, *, ?, ", <, >, |, ` ` (space character), ,, #/li>
* <li>Cannot start with -, _, +</li>
* <li>Cannot be . or ..</li>
* <li>Cannot be longer than 255 bytes (note it is bytes, so multi-byte characters will count towards the 255 limit
* faster)</li>
* </ul>
*/
String indexName();
/**
* Use server-side settings when creating the index.
*/
boolean useServerConfiguration() default false;
/**
*默认分片数
* Number of shards for the index {@link #indexName()}. Used for index creation. <br/>
* With version 4.0, the default value is changed from 5 to 1 to reflect the change in the default settings of
* Elasticsearch which changed to 1 as well in Elasticsearch 7.0.
*/
short shards() default 1;
/**
* 默认副本数量
* Number of replicas for the index {@link #indexName()}. Used for index creation.
*/
short replicas() default 1;
/**
* Refresh interval for the index {@link #indexName()}. Used for index creation.
*/
String refreshInterval() default "1s";
/**
* Index storage type for the index {@link #indexName()}. Used for index creation.
*/
String indexStoreType() default "fs";
/**
* Configuration whether to create an index on repository bootstrapping.
*/
boolean createIndex() default true;
/**
* Configuration of version management.
*/
VersionType versionType() default VersionType.EXTERNAL;
}
@Id 表示是文档的id,文档可以认为是mysql中表行的概念
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface Id {
}
@Field
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
@Documented
@Inherited
public @interface Field {
//文档中字段的类型
FieldType type() default FieldType.Auto;
//是否建立倒排索引
boolean index() default true;
DateFormat format() default DateFormat.none;
String pattern() default "";
//是否进行存储
boolean store() default false;
boolean fielddata() default false;
String searchAnalyzer() default "";
//分词器名次
String analyzer() default "";
String normalizer() default "";
String[] ignoreFields() default {};
boolean includeInParent() default false;
String[] copyTo() default {};
}
为文档自动指定元数据类型
public enum FieldType {
Text,//会进行分词并建了索引的字符类型
Integer,
Long,
Date,
Float,
Double,
Boolean,
Object,
Auto,//自动判断字段类型
Nested,//嵌套对象类型
Ip,
Attachment,
Keyword;//不会进行分词建立索引的类型
private FieldType() {
}
}
在SpringBoot data Elasticsearch 操作方式有2种:一种是继承ElasticsearchRepository接口,另一种是ElasticsearchTemplate.
第一种方式:继承ElasticsearchRepository<T, ID extends Serializable>接口
先创建实体类
/**
* 搜索商品的信息
*/
@Data
@EqualsAndHashCode(callSuper = false)
//indexName 索引库名次,mysql中数据库的概念
//type 类型
//shards 默认分片数
//replicas 默认副本数量
@Document(indexName = "pms",type = "product",shards = 1,replicas = 0)
public class EsProduct implements Serializable {
private static final long serialVersionUID = -1L;
@Id
private Long id;
@Field(type = FieldType.Keyword)
private String productSn;
private Long brandId;
@Field(type = FieldType.Keyword)
private String brandName;
@Field(type = FieldType.Keyword)
private String productCategoryName;
private String pic;
@Field(analyzer = "ik_max_word",type = FieldType.Text)
private String name;
@Field(analyzer = "ik_max_word",type = FieldType.Text)
private String subTitle;
@Field(analyzer = "ik_max_word",type = FieldType.Text)
private String keywords;
private BigDecimal price;
private Integer sort;
@Field(type =FieldType.Nested)
private List<EsProductAttributeValue> attrValueList;
...get set 方法
继承ElasticsearchRepository<T, ID extends Serializable>接口
/**
* 搜索商品ES操作类
*
* 在接口中直接指定 **查询方法名** 称便可查询,无需进行实现,
* 如商品表中有商品名称、标题和关键字,
* 直接定义以下查询,就可以对这三个字段进行全文搜索。
*/
public interface EsProductRepository extends ElasticsearchRepository<EsProduct,Long> {
/**
* 搜索查询
* @param name 商品名称
* @param subTitle 商品标题
* @param keywords 商品关键字
* @param page 分页信息
* @return
* 必须按提示命名
*/
Page<EsProduct> findByNameOrSubTitleOrKeywords(String name, String subTitle, String keywords, Pageable page);
/**
* "match_all": {}
* @param name
* @param pageable
* @return
*/
// @Query("{"bool" : {"must" : {"field" : {"name" : "?0"}}}}")
Page<EsProduct> findByName(String name,Pageable pageable);
}
EsProductService 实现类
/**
* EsProductService 实现类
*/
@Service
public class EsProductServiceImpl implements EsProductService {
private static final Logger logger = LoggerFactory.getLogger(EsProductServiceImpl.class);
@Autowired
private EsProductDao productDao;
@Autowired
private EsProductRepository productRepository;
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Override
public int importAll() {
//数据库查询所有商品信息
List<EsProduct> esProductList = productDao.getAllEsProductList(null);
logger.info("查询所有商品:{}",esProductList.toString());
//把所有的商品信息放入es中
Iterable<EsProduct> esProductIterable = productRepository.saveAll(esProductList);
Iterator<EsProduct> iterator = esProductIterable.iterator();
int result =0;
while (iterator.hasNext()) {
result++;
iterator.next();
}
//放入了多少条
return result;
}
@Override
public void delete(Long id) {
productRepository.deleteById(id);
}
@Override
public EsProduct create(Long id) {
EsProduct result = null;
List<EsProduct> esProductList = productDao.getAllEsProductList(id);
//从数据库中查询商品,把商品放入es中
if (esProductList.size() > 0){
EsProduct esProduct = esProductList.get(0);
result = productRepository.save(esProduct);
}
return result;
}
@Override
public void delete(List<Long> ids) {
//org.springframework.util.CollectionUtils;
if ( !CollectionUtils.isEmpty(ids) ){
List<EsProduct> esProductList = new ArrayList<>();
for (Long id:ids){
EsProduct esProduct = new EsProduct();
esProduct.setId(id);
esProductList.add(esProduct);
}
productRepository.deleteAll(esProductList);
}
}
@Override
public Page<EsProduct> search(String keyword, Integer pageNum, Integer pageSize) {
// 分页
Pageable pageable = PageRequest.of(pageNum,pageSize);
//
// QueryBuilder queryBuilder = QueryBuilders.boolQuery()
// .must(QueryBuilders.matchQuery("name",keyword))
// .must(QueryBuilders.matchQuery("subTitle",keyword))
// .must(QueryBuilders.matchQuery("keywords",keyword));
QueryBuilder queryBuilder = QueryBuilders.boolQuery()
.must(QueryBuilders.matchQuery("name",keyword))
.must(QueryBuilders.matchQuery("subTitle",keyword))
.must(QueryBuilders.matchQuery("keywords",keyword));
// return productRepository.search(queryBuilder,pageable);
return productRepository.findByNameOrSubTitleOrKeywords(keyword,keyword,keyword,pageable);
}
@Override
public List<EsProduct> searchAll() {
Iterable<EsProduct> iterable = productRepository.findAll();
Iterator<EsProduct> iterator = iterable.iterator();
List<EsProduct> list = new ArrayList<>();
while (iterator.hasNext()){
list.add(iterator.next());
}
return list;
}
@Override
public Page<EsProduct> searchByName(String keyword, Integer pageNum, Integer pageSize) {
// 分页
Pageable pageable = PageRequest.of(pageNum,pageSize);
return productRepository.findByName(keyword,pageable);
}
}
第二种方式:ElasticsearchTemplate
org.springframework.data.elasticsearch.core.ElasticsearchTemplate
创建数据
org.springframework.data.elasticsearch.core.query.IndexQuery;
//创建单条数据
public String index(IndexQuery query) {}
//创建单条数据
public <T> boolean createIndex(Class<T> clazz) {}
//批量创建数据
public void bulkIndex(List<IndexQuery> queries) {}
public void addAll( EsProduct esProduct ){
IndexQuery indexQuery = new IndexQueryBuilder()
.withId(esProduct.getProductSn())
.withObject(esProduct)
.build();
//创建单条数据
elasticsearchTemplate.index(indexQuery);
elasticsearchTemplate.createIndex(EsProduct.class);
//批量创建数据
List<IndexQuery> indexQueryList = new ArrayList<>();
indexQueryList.add(new IndexQueryBuilder().withId("")
.withIndexName("索引名称").withObject(esProduct).build());
indexQueryList.add(new IndexQueryBuilder().withId("")
.withIndexName("索引名称").withObject(esProduct).build());
elasticsearchTemplate.bulkIndex(indexQueryList);
}
删除数据
//根据类对象删除
public <T> boolean deleteIndex(Class<T> clazz) {}
// 根据索引名删除
public boolean deleteIndex(String indexName) {}
//
//org.springframework.data.elasticsearch.core.query.DeleteQuery
//org.elasticsearch.index.query.QueryBuilder
public <T> void delete(DeleteQuery deleteQuery, Class<T> clazz) {}
更新数据
//单个更新
//org.springframework.data.elasticsearch.core.query.UpdateQuery;
//org.elasticsearch.action.update.UpdateRequest;
//org.springframework.data.elasticsearch.core.query.UpdateQueryBuilder
public UpdateResponse update(UpdateQuery query) {}
// 批量更新
public void bulkUpdate(List<UpdateQuery> queries) {}
查询
//
//org.springframework.data.elasticsearch.core.query.SearchQuery;
//org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
//org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
public <T> List<String> queryForIds(SearchQuery query) {}
//
public <T> List<T> queryForList(StringQuery query, Class<T> clazz){}
//
public <T> T queryForObject(StringQuery query, Class<T> clazz) {}
//
public <T> AggregatedPage<T> queryForPage(SearchQuery query, Class<T> clazz) {}
//
//org.springframework.data.elasticsearch.core.query.CriteriaQuery ;
//org.springframework.data.elasticsearch.core.query.Criteria;
public <T> List<T> queryForList(CriteriaQuery query, Class<T> clazz) {}
示例
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.queryStringQuery("小米"))
.withPageable(new PageRequest(0, 20))
.build();
List<EsProduct> list = elasticsearchTemplate.queryForList(searchQuery, EsProduct.class);
//排序
Pageable pageable= new PageRequest(0, 20,new Sort(Sort.Direction.DESC, "name"));
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.queryStringQuery("华为"))
.withPageable(pageable)
.build();
Page<EsProduct> list = elasticsearchTemplate.queryForPage(searchQuery, EsProduct.class);
//模糊查找
Pageable pageable = new PageRequest(0, 10);
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchQuery("name", "苹果"))
.withPageable(pageable)
.build();
List<EsProduct> list = elasticsearchTemplate.queryForList(searchQuery, EsProduct.class);
//Term全等查询
Pageable pageable = new PageRequest(0, 10);
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.termQuery("name", "华为"))
.withPageable(pageable)
.build();
List<EsProduct> list = elasticsearchTemplate.queryForList(searchQuery, EsProduct.class);
//组合查询
QueryBuilder filterQuery = QueryBuilders
.boolQuery()
.filter(QueryBuilders.termQuery("name", "小米"))
.filter(QueryBuilders.termQuery("author", "雷军"));
SearchQuery searchQuerys = new NativeSearchQueryBuilder().withQuery(filterQuery).build();
List<EsProduct> lists = elasticsearchTemplate.queryForList( searchQuerys, EsProduct.class);