突然接到一个搜索的项目,需要新增一个版本,后台页面数据是存放在ElasticSearch中的,由于之前在实际项目当中从未用过ES,再加上只给了两天时间就需要完成页面和接口的开发,所以显得有些局促,不过好歹顺利完成,将学到的ES使用记录下来。
本文是通过spring-data-elasticsearch来操作ES的
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
/dependency>
spring:
data:
elasticsearch:
cluster-name: elasticsearch #注意
cluster-nodes: 127.0.0.1:9200 # 多个节点用逗号分开
注意:配置cluster-name的时候值一定要与下图红线框起来的一致。
想要操作ES中的索引是需要创建一个实体类
例如我所需要操作的是一个广告类:
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
/**
* 广告索引
*
*/
@Data
@Document(indexName = "adsInfos", type = "adsType", shards = 6, replicas = 2, refreshInterval = "0s")
public class Es_AdsInfo {
@Id
private Object id;
@Field
private Object adsName; //广告图名称
@Field
private Object adsTypes; //广告图类型
@Field
private Object adsKeyWords;//匹配关键字
@Field
private Object adsStartTime;//推广开始时间
@Field
private Object adsEndTime;//推广结束时间
@Field
private Object adsPCImg;//PC端广告图地址
@Field
private Object adsMobileImg;//移动端广告图地址
@Field
private Object adsPCLink;//PC端跳转地址
@Field
private Object adsMobileLink;//移动端跳转地址
@Field
private Object addTime;//添加时间段
@Field
private Object insertDateTime; //入库时间
@Field
private Object updateDateTime; //更新时间
@Field
private Object field1; //备用字段
@Field
private Object field2; //备用字段
@Field
private Object field3; //备用字段
@Field
private Object field4; //备用字段
@Field
private Object field5; //备用字段
}
在实体类中可以看到有一个@Document注解,里面有indexName,type,shards,replicas,refreshInterval
事先声明:ES中的索引类似于普通关系型数据库(如:mysql,sqlserver)的数据库,而ES中的type则相当于数据库中的表。
以上几个参数必须要有indexName 和 type 其他三个可以不写
比如可以这样
@Document(indexName = "adsInfos", type = "adsType"")
使用ElasticsearchTemplate完全不需要有Dao层和service层,直接controller附带一个实体类就搞定一切。话不多说,上代码。
/**
* 数据查找
*
* @return
*/
@RequestMapping(value = "getPageList", method = RequestMethod.GET)
public Page<Es_KuaiSou_AdsInfo> findPageList(@PageableDefault(size = 12) Pageable pageable, @RequestParam(name="title",required = false)String title) {
SortBuilder sortBuilder = SortBuilders.fieldSort("insertDateTime").order(SortOrder.DESC);
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchAllQuery()).withSort(sortBuilder).withPageable(pageable).build();
Page<Es_KuaiSou_AdsInfo> perfect_indices = elasticsearchTemplate.queryForPage(searchQuery, Es_KuaiSou_AdsInfo.class);
return perfect_indices;
}
完全没有看错,简简单单的三两行代码搞定查询。
但需要注意一下几点,如何使用条件查询?排序?分页查询?
如果想要使用条件查询的话只需要在NativeSearchQueryBuilder后点一个withQuery对象出来withQuery(字段名,参数)
效果:
new NativeSearchQueryBuilder().withQuery(matchQuery("adsName","开屏广告"))
这就是对adsName字段进行筛选,查出adsName等于开屏广告的数据
想要按某个字段排序的话就需要new一个SortBuilder对象
SortBuilder sortBuilder = SortBuilders.fieldSort("time").order(SortOrder.DESC);
创建完SortBuilder 对象以后再new NativeSearchQueryBuilder()后边点一个withSort()把sortBuilder 对象放括号里
效果:
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withSort(sortBuilder).build();
因为ES默认只返回10条数据,想要每页多返回几条需要创建Pageable对象
比如我这里是在查询方法加了注解@PageableDefault(size = 12) Pageable pageable,改为ES默认返回12条数据。
效果:
SearchQuery searchQuery = new NativeSearchQueryBuilder().withPageable(pageable).build();
当所有查询条件都就位之后效果是这样的:
SortBuilder sortBuilder = SortBuilders.fieldSort("time").order(SortOrder.DESC);
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("adsName","开屏广告")).withSort(sortBuilder).withPageable(pageable).build();
然后再将SearchQuery 对象交给elasticsearchTemplate.queryForPage()
最终效果:
/**
* 数据查找
*
* @return
*/
@RequestMapping(value = "getPageList", method = RequestMethod.GET)
public Page<Es_AdsInfo> findPageList(@PageableDefault(size = 12) Pageable pageable, @RequestParam(name="adsName",required = false)String adsName) {
SortBuilder sortBuilder = SortBuilders.fieldSort("time").order(SortOrder.DESC);
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchQuery("adsName",adsName).withSort(sortBuilder).withPageable(pageable).build();
Page<Es_AdsInfo> perfect_indices = elasticsearchTemplate.queryForPage(searchQuery, Es_AdsInfo.class);
return perfect_indices;
}
这里增改在一个方法里实现了,当新增数据时生成的id在ES里查找不到就会新增一条数据,当修改的时候由于ES里已经存在一个一模一样id的数据,此时就是对这条数据进行了修改。
/**
* 数据添加/修改
*
* @return
*/
@RequestMapping(value = "save", method = RequestMethod.POST)
public void save(@RequestBody Es_AdsInfo es_AdsInfo) throws IOException {
//修改数据
String id = UUID.randomUUID().toString();
if(null == es_AdsInfo.getId()){
es_AdsInfo.setId(id);
}
List<IndexQuery> queries = new ArrayList<>();
IndexQuery indexQuery = new IndexQuery();
indexQuery.setId(es_AdsInfo.getId().toString());
indexQuery.setObject(es_AdsInfo);
indexQuery.setIndexName("adsInfos");
indexQuery.setType("adsType");
queries.add(indexQuery);
elasticsearchTemplate.bulkIndex(queries);
}
删除的话把id传过来使用elasticsearchTemplate执行delete操作就可以了。
delete(“adsInfos”,“adsType”,id)
我们看到delete方法中有三个参数,分别为索引名称,索引类型,和要删除数据的id。
/**
* 数据删除
*
* @return
*/
@RequestMapping(value = "deleted", method = RequestMethod.DELETE)
public void deleted(String id) {
elasticsearchTemplate.delete("adsInfos","adsType",id);
}