ES操作
程序员文章站
2022-07-06 15:46:47
...
ES基本使用
导包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
一、准备启动类
二、写配置文件 application.yml
spring:
application:
name: hrm-es-server #服务名
data:
elasticsearch:
cluster-name: elasticsearch
cluster-nodes: 127.0.0.1:9300 #9200是图形界面端,9300代码端
三、创建实体类 为EmpDoc做文档映
@Document(indexName = "cms", type = "user")
@Data
public class UserDoc {
//对应文档的id
@Id
private Long id;
//用户名
@Field(type = FieldType.Keyword)
private String username;
//介绍 analyzer
@Field(type = FieldType.Text, analyzer = "ik_smart", searchAnalyzer = "ik_smart")
private String intro;
//年龄
@Field(type = FieldType.Integer)
private Integer age;
//性别
@Field(type = FieldType.Integer)
private Integer sex;
}
四、写一个repository
@Repository
public interface UserElasticRepository extends ElasticsearchRepository<UserDoc,Long> {
}
五、配置mapper
package cn.itsource.mapper;
import com.alibaba.fastjson.JSON;
import net.minidev.json.JSONObject;
import org.assertj.core.util.Lists;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
@Component
public class HighlightResultMapper implements SearchResultMapper {
@Override
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> aClass, Pageable pageable) {
// 记录总条数
long totalHits = response.getHits().getTotalHits();
// 记录列表(泛型) - 构建Aggregate使用
List<T> list = Lists.newArrayList();
// 获取搜索结果(真正的的记录)
SearchHits hits = response.getHits();
for (SearchHit hit : hits) {
if(hits.getHits().length <= 0){
return null;
}
// 将原本的JSON对象转换成Map对象
Map<String, Object> map = hit.getSourceAsMap();
// 获取高亮的字段Map
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
for (Map.Entry<String, HighlightField> highlightField : highlightFields.entrySet()) {
// 获取高亮的Key
String key = highlightField.getKey();
// 获取高亮的Value
HighlightField value = highlightField.getValue();
// 实际fragments[0]就是高亮的结果,无需遍历拼接
Text[] fragments = value.getFragments();
StringBuilder sb = new StringBuilder();
for (Text text : fragments) {
sb.append(text);
}
// 因为高亮的字段必然存在于Map中,就是key值
// 可能有一种情况,就是高亮的字段是嵌套Map,也就是说在Map里面还有Map的这种情况,这里没有考虑
map.put(key, sb.toString());
}
// 把Map转换成对象
T item = JSON.parseObject(JSONObject.toJSONString(map),aClass);
list.add(item);
}
// 返回的是带分页的结果
return new AggregatedPageImpl<>(list, pageable, totalHits,response.getAggregations());
}
}
六、Test测试
@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
public class ESTest {
@Autowired
private ElasticsearchTemplate template;
@Autowired
private UserElasticRepository repository;
@Autowired
private HighlightResultMapper resultMapper;
/**
* 1.创建索引库
* 2.做文档映射
* 3.存储文档数据
*/
@Test
public void testCreateIndex() {
//创建索引
template.createIndex(UserDoc.class);
//创建映射
template.putMapping(UserDoc.class);
}
/**
* 批量添加数据
*
* @return
*/
public List<UserDoc> createDataInBulk() {
List<UserDoc> list = new ArrayList<>();
UserDoc userDoc = null;
for (int i = 1; i <= 50; i++) {
if (i % 2 == 0) {
userDoc = new UserDoc(Long.valueOf(i), "王小二", "我今晚打小徐" + i + "次", 12 + i, 1);
list.add(userDoc);
} else {
userDoc = new UserDoc(Long.valueOf(i), "王小翠", "我今晚帮助王小二打小徐" + i + "次", 10 + i, 0);
list.add(userDoc);
}
}
return list;
}
/**
* 添加文档数据
*/
@Test
public void testAddDocumentData() {
/* UserDoc userDoc = new UserDoc(1L, "王甜甜", "我是一个可爱的女生", 18, 0);*/
List<UserDoc> userDoc = createDataInBulk();
repository.saveAll(userDoc);
System.out.println("操作成功.....");
}
/**
* 修改文档数据
*/
@Test
public void testUpdateDocumentData() {
//创建一个userDoc对象
UserDoc userDoc = new UserDoc(1L, "李建", "我是一个可爱的男孩", 20, 1);
//将userDoc对象添加到文档数据库中
repository.save(userDoc);
System.out.println("操作成功.....");
}
/**
* 查询文档数据
*/
@Test
public void testSearchDocumentData() {
//根据id查询文档数据
Optional<UserDoc> optional = repository.findById(1L);
//获取查询出来的数据
UserDoc userDoc = null;
try {
userDoc = optional.get();
System.out.println(userDoc);
} catch (NoSuchElementException e) {
System.out.println("数据为空");
e.printStackTrace();
}
}
/**
* 删除文档数据
*/
@Test
public void testDeleteDocumentData() {
repository.deleteById(1L);
System.out.println("删除成功...");
}
/**
* 高级文档查询
* 查询 username 中叫 “ 王小翠 ”的人,简介包含:“今晚”,年龄在 18 - 35之间的 ,性别为 女 按照年龄进行降序排序,显示第2页的数据,每页展示5条数据,
*/
@Test
public void testAdvancedDocumentQuery() {
//构建查询对象
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
//分页 显示第2页的数据,每页展示5条数据,
builder.withPageable(PageRequest.of(0, 5));
//排序 按照年龄进行降序排序
builder.withSort(SortBuilders.fieldSort("age").order(SortOrder.DESC));
//查询条件
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//标准查询 查询 username 中叫 “ 王小二 ”的人
boolQueryBuilder.must(QueryBuilders.termQuery("username", "王小二"));
//过滤查询 简介包含:“今晚”,年龄在 18 - 35之间的 ,性别为 女
boolQueryBuilder.filter(QueryBuilders.rangeQuery("age").gte(18).lte(35))
.filter(QueryBuilders.termQuery("sex", 1))
.filter(QueryBuilders.matchQuery("intro", "今晚"));
//添加到查询语句中
builder.withQuery(boolQueryBuilder);
//构建一个查询对象
NativeSearchQuery build = builder.build();
//执行查询
Page<UserDoc> page = repository.search(build);
//处理结果
System.out.println("命中总条数:" + page.getTotalElements());
System.out.println("命中总页数:" + page.getTotalPages());
//查询结果
page.forEach(System.out::println);
}
/**
* 高亮查询
*/
@Test
public void testHighlightQuery() {
//构建查询对象
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
//分页 显示第2页的数据,每页展示5条数据,
builder.withPageable(PageRequest.of(0, 5));
//排序 按照年龄进行降序排序
builder.withSort(SortBuilders.fieldSort("age").order(SortOrder.DESC));
//查询条件
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//标准查询 查询 username 中叫 “ 王小二 ”的人
boolQueryBuilder.must(QueryBuilders.termQuery("username", "王小翠"));
//过滤查询 简介包含:“今晚”,年龄在 18 - 35之间的 ,性别为 女
boolQueryBuilder.filter(QueryBuilders.rangeQuery("age").gte(18).lte(35))
.filter(QueryBuilders.termQuery("sex", 0))
.filter(QueryBuilders.matchQuery("intro", "帮助"));
//添加到查询语句中
builder.withQuery(boolQueryBuilder);
//构建一个查询对象
NativeSearchQuery build = builder.build();
//执行查询
//设置高亮显示===========================================
HighlightBuilder.Field field = new HighlightBuilder.Field("intro").preTags("<font style='color:red'>").postTags("</font>");
builder.withHighlightFields(field);
//执行查询
AggregatedPage<UserDoc> userDocs = template.queryForPage(build, UserDoc.class, resultMapper);
//处理结果
System.out.println("命中总条数:" + userDocs.getTotalElements());
System.out.println("命中总页数:" + userDocs.getTotalPages());
//查询结果
userDocs.forEach(System.out::println);
}
/**
* 聚合查询
*/
@Test
public void testAggregationQuery() {
//构建查询对象
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
//分页 显示第2页的数据,每页展示5条数据,
builder.withPageable(PageRequest.of(0, 5));
//排序 按照年龄进行降序排序
builder.withSort(SortBuilders.fieldSort("age").order(SortOrder.DESC));
//查询条件
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//标准查询 查询 username 中叫 “ 王小二 ”的人
boolQueryBuilder.must(QueryBuilders.termQuery("username", "王小翠"));
//过滤查询 简介包含:“今晚”,年龄在 18 - 35之间的 ,性别为 女
boolQueryBuilder.filter(QueryBuilders.rangeQuery("age").gte(18).lte(35))
.filter(QueryBuilders.termQuery("sex", 0))
.filter(QueryBuilders.matchQuery("intro", "帮助"));
//添加到查询语句中
builder.withQuery(boolQueryBuilder);
//构建一个查询对象
NativeSearchQuery build = builder.build();
//执行查询
//聚合查询
TermsAggregationBuilder tenantAgg = AggregationBuilders.terms("sex").field("sex")
.order(Terms.Order.count(false)).size(10); //按照count倒排
builder.addAggregation(tenantAgg);
AggregatedPage<UserDoc> userDocs = template.queryForPage(builder.build(), UserDoc.class, resultMapper);
//处理结果
System.out.println("命中总条数:" + userDocs.getTotalElements());
System.out.println("命中总页数:" + userDocs.getTotalPages());
//查询结果
userDocs.forEach(System.out::println);
//获取聚合结果
LongTerms terms = (LongTerms) userDocs.getAggregation("sex");
List<LongTerms.Bucket> buckets = terms.getBuckets();
for (LongTerms.Bucket bucket : buckets) {
if (1 == (Long) bucket.getKey()) {
System.out.println("男生有:" + bucket.getDocCount());
} else {
System.out.println("女生有:" + bucket.getDocCount());
}
}
//把机构名字聚合,搜集成字符串里集合
// List<String> collect = buckets.stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
}
}
七、web.controller操作
@RestController
@RequestMapping("/search")
public class SearchCourseController {
@Autowired
private SearchElasticRepository repository;
@Autowired
private ElasticsearchTemplate template;
@Autowired
private HighlightResultMapper highlightResultMapper;
/**
* 添加全文搜索的信息和展示字段
*
* @param courseQuery
* @return
*/
@RequestMapping(value = "/course/queryCourses", method = RequestMethod.POST)
public AjaxResult queryCourses(@RequestBody CourseQuery courseQuery) {
//构建查询对象
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
BoolQueryBuilder boolQueryBuilder = getQueryBuilder(courseQuery, builder);
builder.withQuery(boolQueryBuilder);
//给对应的字段设置高亮========================================
HighlightBuilder.Field field = new HighlightBuilder.Field("name").preTags("<font style='color:red'>").postTags("</font>");
builder.withHighlightFields(field);
//设置聚合==================================================
TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("tenantName").field("tenantName")
.order(Terms.Order.count(false)).size(10);
builder.addAggregation(termsAggregationBuilder);
//构建一个查询对象
NativeSearchQuery build = builder.build();
//执行查询
AggregatedPage<SearchDoc> page = template.queryForPage(build, SearchDoc.class, highlightResultMapper);
StringTerms terms = (StringTerms) page.getAggregation("tenantName");
List<SearchVo> list = new ArrayList<>();
terms.getBuckets().stream().map(bucket -> list.add(new SearchVo(bucket.getDocCount(), bucket.getKeyAsString()))).collect(Collectors.toList());
//处理结果
return AjaxResult.me().setResultObj(new SearchDocQuery(page.getTotalPages(), page.getContent(), list));
}
/**
* 构建查询对象
*
* @param courseQuery
* @param builder
* @return
*/
private BoolQueryBuilder getQueryBuilder(CourseQuery courseQuery, NativeSearchQueryBuilder builder) {
//分页=====================================================
builder.withPageable(PageRequest.of(courseQuery.getPage() - 1, courseQuery.getRows()));
//排序=====================================================
builder.withSort(SortBuilders.fieldSort(courseSort(courseQuery))
.order("desc".equalsIgnoreCase(courseQuery.getSortType()) ? SortOrder.DESC : SortOrder.ASC));
//条件查询==================================================
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
if (StringUtils.hasLength(courseQuery.getKeyword())) {
String keyword = courseQuery.getKeyword();
boolQueryBuilder.must(QueryBuilders.termQuery("name", keyword));
}
if (!(courseQuery.getCourseTypeId() == null)) {
Long courseTypeId = courseQuery.getCourseTypeId();
boolQueryBuilder.filter(QueryBuilders.termQuery("courseTypeId", courseTypeId));
}
if (!(courseQuery.getPriceMin() == null)) {
Float priceMin = courseQuery.getPriceMin();
boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(priceMin));
}
if (!(courseQuery.getPriceMax() == null)) {
Float priceMax = courseQuery.getPriceMax();
boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").lte(priceMax));
}
if (StringUtils.hasLength(courseQuery.getTenantName())) {
String tenantName = courseQuery.getTenantName();
boolQueryBuilder.filter(QueryBuilders.termQuery("tenantName", tenantName));
}
return boolQueryBuilder;
}
/**
* 按照什么字段排序
*/
public String courseSort(CourseQuery courseQuery) {
String sortField = courseQuery.getSortField();
if (StringUtils.hasLength(sortField)) {
switch (sortField) {
case "xp":
return "onlinkDate";
case "pl":
return "commentCount";
case "jg":
return "price";
case "rq":
return "viewCount";
}
}
return "saleCount";
}
/**
* 添加全文搜索的信息和展示字段
*
* @param searchDoc
* @return
*/
@PreAuthorize("hasAuthority('es:online')")
@RequestMapping("/addToCourseResearchAll")
public AjaxResult addToCourseResearchAll(@RequestBody SearchDoc searchDoc) {
repository.save(searchDoc);
return AjaxResult.me();
}
}
上一篇: Clickhouse单机安装记录