spring-data-elasticsearch
- spring-data-elasticsearch是比较好用的一个elasticsearch客户端,本文介绍如何使用它来操作ES。本文使用spring-boot-starter-data-elasticsearch,它内部会引入spring-data-elasticsearch。
API对比
- Spring Data ElasticSearch有下边这几种方法操作ElasticSearch:
ElasticsearchRepository(传统的方法,可以使用)
ElasticsearchRestTemplate(推荐使用。基于RestHighLevelClient)
ElasticsearchTemplate(ES7中废弃,不建议使用。基于TransportClient)
RestHighLevelClient(推荐度低于ElasticsearchRestTemplate,因为API不够高级)
TransportClient(ES7中废弃,不建议使用)
CRUD
ElasticsearchRestTemplate+RestHighLevelClient(批量更新)
@Test
public void esTestIndex() throws IOException {
boolean exists = restTemplate.indexOps(Student.class).exists();
System.out.println("es判断============>"+exists);
// boolean b = restTemplate.indexOps(Student.class).create();
// System.out.println("es创建============>"+b);
//新增文档
Student student = new Student();
student.setId("10001");
student.setName("tomm");
student.setAge(18);
// Student save = restTemplate.save(student);
// System.out.println("id======>"+save.getId());
Student student1 = new Student();
student1.setId("10002");
student1.setName("jerry");
student1.setAge(20);
//自增返回值
IndexQuery queryBuilder = new IndexQueryBuilder()
.withId(student1.getId())
.withObject(student1)
.build();
// String id1 = restTemplate.index(queryBuilder, IndexCoordinates.of("student_index"));
// System.out.println("id1================>"+id1);
//批量增加
Student student3 = new Student();
student3.setId("10006");
student3.setName("java java");
student3.setAge(60);
Student student4 = new Student();
student4.setId("10007");
student4.setName("php java");
student4.setAge(65);
List<Student> students = new ArrayList<>();
students.add(student3);
students.add(student4);
// restTemplate.save(students);
// String del = restTemplate.delete("GyPCdI4BtZyq3y0dU9FK", Student.class);
// String del1 = restTemplate.delete("HCPCdI4BtZyq3y0dU9FP", Student.class);
// String del2 = restTemplate.delete("HSPEdI4BtZyq3y0dxdHe", Student.class);
// System.out.println("del===========>"+del);
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
boolQuery.must(QueryBuilders.termQuery("name","cat"));
boolQuery.must(QueryBuilders.termQuery("age",24));
// Query searchQuery = new NativeSearchQuery(boolQuery);
// restTemplate.delete(searchQuery, Student.class,IndexCoordinates.of("student_index"));
//查询全部
QueryBuilder queryBuilder1 = QueryBuilders.matchAllQuery();
//精确查询 =
QueryBuilder queryBuilder2 = QueryBuilders.termQuery("name", "dog");
//精确查询 in
QueryBuilder queryBuilder3 = QueryBuilders.termsQuery("name", "dog", "tomm");
//分词匹配
QueryBuilder queryBuilder4 = QueryBuilders.matchQuery("name", "tomm m");
QueryBuilder queryBuilder5 = QueryBuilders.matchQuery("name", "tomm m").analyzer("ik_max_word");
//多个字段匹配
QueryBuilder queryBuilder6 = QueryBuilders.multiMatchQuery("dog", "name");
//模糊查询,测试结果:dog dos dogg可以,do doggg不可以
QueryBuilder queryBuilder7 = QueryBuilders.fuzzyQuery("name","dogg");
//前缀查询
QueryBuilder queryBuilder8 = QueryBuilders.prefixQuery("name", "t");
//通配符查询
QueryBuilder queryBuilder9 = QueryBuilders.regexpQuery("name.keyword", "^d.*");
//多条件查询
BoolQueryBuilder queryBuilder10 = QueryBuilders.boolQuery();
//and
queryBuilder10.must(QueryBuilders.termQuery("name","dog"));
//or
queryBuilder10.should(QueryBuilders.termQuery("name","dog"));
queryBuilder10.should(QueryBuilders.termQuery("age",18));
//不等于
BoolQueryBuilder queryBuilder11 = QueryBuilders.boolQuery();
queryBuilder11.mustNot(QueryBuilders.termQuery("age",12));
//过滤数据
BoolQueryBuilder queryBuilder12 = QueryBuilders.boolQuery();
// queryBuilder12.filter(QueryBuilders.matchQuery("name","dog"));
queryBuilder12.filter(QueryBuilders.termQuery("name","dog"));
//范围查询
BoolQueryBuilder queryBuilder13 = QueryBuilders.boolQuery();
// queryBuilder13.filter(new RangeQueryBuilder("age").gt(19).lte(23));
//分页
Pageable pageable = PageRequest.of(0, 2);
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(queryBuilder13)
.withPageable(pageable)
//排序
.withSorts(SortBuilders.fieldSort("_score").order(SortOrder.DESC))
.build();
//除分页的其他查询,将此注释解开
// Query searchQuery = new NativeSearchQuery(queryBuilder13);
SearchHits<Student> searchHits = restTemplate.search(searchQuery, Student.class);
System.out.println("searchHits=========>"+searchHits);
Stream<SearchHit<Student>> hitStream = searchHits.get();
System.out.println("hitStream=========>"+hitStream);
List<Student> studentList = hitStream.map(SearchHit::getContent).collect(Collectors.toList());
studentList.forEach(student2 -> System.out.println(student2.toString()));
//覆盖修改
Student st = new Student("10001","覆盖修改",99);
// restTemplate.save(st);
//根据id修改
// UpdateQuery updateQuery = UpdateQuery.builder("10001").build();
Document document = Document.create();
document.putIfAbsent("name","根据id修改a");
UpdateQuery updateQuery = UpdateQuery.builder("10001")
.withDocument(document)
.withRetryOnConflict(3)
.withDocAsUpsert(true)
.build();
// UpdateResponse response = restTemplate.update(updateQuery, IndexCoordinates.of("student_index"));
// System.out.println("resp==================>"+response.getResult());
//根据条件批量更新
UpdateByQueryRequest studentIndex = new UpdateByQueryRequest("student_index");
//版本冲突
studentIndex.setConflicts("proceed");
//设置查询条件
BoolQueryBuilder query = QueryBuilders.boolQuery();
query.must(QueryBuilders.termQuery("name","jerry"));
studentIndex.setQuery(query);
//批次大小
studentIndex.setBatchSize(1000);
//并行
studentIndex.setSlices(2);
//使用滚动参数来控制”搜索上下文“存活的时间
studentIndex.setScroll(TimeValue.timeValueMillis(10));
//刷新索引
studentIndex.setRefresh(true);
//更新内容
studentIndex.setScript(new Script("ctx._source['name']='test01'"));
BulkByScrollResponse bulk = restHighLevelClient.updateByQuery(studentIndex, RequestOptions.DEFAULT);
System.out.println("bulk============>"+bulk.getStatus().getUpdated());
}
高亮查询
@Override
public List<Content> searchPage(String keywords, Integer pageNo, Integer pageSize) {
// 将关键词转换为小写
keywords = keywords.toLowerCase();
PageRequest pageRequest = PageRequest.of(pageNo, pageSize);
QueryBuilder title = QueryBuilders.termQuery("title", keywords);
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withPageable(pageRequest)
.withHighlightFields(new HighlightBuilder
.Field("title")
.preTags("<span style='color: red'>")
.postTags("</span>").requireFieldMatch(false)
)
.withQuery(title)
.build();
SearchHits<Content> jdGoods = restTemplate.search(searchQuery, Content.class, IndexCoordinates.of("jd_goods"));
// Stream<SearchHit<Content>> searchHitStream = jdGoods.get();
// List<Content> contentList = searchHitStream.map(SearchHit::getContent).collect(Collectors.toList());
List<Content> contentList = jdGoods.stream().map(new Function<SearchHit<Content>, Content>() {
@Override
public Content apply(SearchHit<Content> hit) {
Map<String, List<String>> fields = hit.getHighlightFields();
List<String> title = fields.get("title");
Content content = hit.getContent();
if (title !=null && !title.isEmpty()){
String s = title.get(0);
content.setTitle(s);
return content;
}
return content;
}
}).collect(Collectors.toList());
return contentList;
}
未解决的问题
- 高亮查询中 requireFieldMatch(false) 似乎是不生效的,无论是true和false均显示一样的效果。
- 正常情况下,不应该是一条数据中第一个关键字高亮吗?为什么所有一条数据中的所有关键字都高亮?欢迎各位大佬评论区解释!
https://blog.csdn.net/weixin_48052161/article/details/136628141
https://blog.csdn.net/qq_43692950/article/details/122285770