Spring Data Elasticsearch是Spring Data项目下的一个子模块。
查看 Spring Data的官网:链接
Spring Data的使命是为数据访问提供熟悉且一致的基于Spring的编程模型,同时仍保留底层数据存储的特殊特性。
它使得使用数据访问技术,关系数据库和非关系数据库,map-reduce框架和基于云的数据服务变得容易。
这是一个总括项目,其中包含许多特定于给定数据库的子项目。
这些令人兴奋的技术项目背后,是由许多公司和开发人员合作开发的。
Spring Data 的使命是给各种数据访问提供统一的编程接口,不管是关系型数据库(如MySQL),还是非关系数据库(如Redis),或者类似Elasticsearch这样的索引数据库。从而简化开发人员的代码,提高开发效率。
包含很多不同数据操作的模块:
Spring Data Elasticsearch的页面:链接
特征:
@Configuration
的java配置方式,或者XML配置方式ElasticsearchTemplate
**。包括实现文档到POJO之间的自动智能映射。使用Spring Data Elasticsearch 版本必须对应elasticsearch服务实例,否则会出现一些报错信息
新建一个demo,学习Elasticsearch
pom核心依赖:
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-data-elasticsearch
org.springframework.boot
spring-boot-starter-test
test
org.projectlombok
lombok
application.yml文件配置(没有配置用户名和密码无需输入):
spring:
elasticsearch:
rest:
uris: localhost:9200
#username:
#password:
Spring Data通过注解来声明字段的映射属性,有下面的三个注解:
@Document
在类级别应用,以指示该类是映射到数据库的候选对象。最重要的属性是:
@Id
作用在成员变量,标记一个字段作为id主键@Transient
:默认情况下,存储或检索文档时,所有字段都映射到文档,此注释不包括该字段。@PersistenceConstructor
: 标记从数据库实例化对象时要使用的给定构造函数,甚至是受保护的程序包。构造函数参数按名称映射到检索到的Document中的键值。@Field
作用在成员变量,标记为文档的字段,并指定字段映射属性:
analyzer和search_analyzer的区别
分析器主要有两种情况会被使用:
第一种是插入文档时,将text类型的字段做分词然后插入倒排索引,
第二种就是在查询时,先对要查询的text类型的输入做分词,再去倒排索引搜索
如果想要让 索引 和 查询 时使用不同的分词器,ElasticSearch也是能支持的,只需要在字段上加上search_analyzer参数
在索引时,只会去看字段有没有定义analyzer,有定义的话就用定义的,没定义就用ES预设的
在查询时,会先去看字段有没有定义search_analyzer,如果没有定义,就去看有没有analyzer,再没有定义,才会去使用ES预设的
ElasticsearchTemplate中提供了创建索引并映射的API运行如下图:
使用kibana控制台查询映射结果:
使用kibana控制台查询结果:
index_not_found_exception(索引删除成功)
public void saveCreate() {
Product product = new Product(1L, "苹果手机",
"手机", "苹果", 8600.00);
//保存 第一种方式
elasticsearchRestTemplate.save(product);
//保存 第二种方式
IndexQuery indexQuery = new IndexQueryBuilder()
.withId(product.getId().toString())
.withObject(product)
.build();
elasticsearchRestTemplate.index(indexQuery, IndexCoordinates.of("product"));
}
GET /product/_search
{
"query": {
"match_all": {}
}
}
public void saveAllCreate() {
List list = new ArrayList<>();
Product product1 = new Product(1L, "小米手机",
"手机", "小米", 3600.00);
list.add(product1);
Product product2 = new Product(2L, "苹果手机",
"手机", "苹果", 8600.00);
list.add(product2);
Product product3 = new Product(3L, "华为手机",
"手机", "华为", 8600.00);
list.add(product3);
Product product4 = new Product(4L, "小米电视",
"电视", "小米", 18600.00);
list.add(product4);
Product product5 = new Product(5L, "华为电视",
"电视", "华为", 28600.00);
list.add(product5);
elasticsearchRestTemplate.save(list);
}
使用kibana控制台查询结果:
修改和新增是同一个接口,区分的依据就是id,这一点跟我们在页面发起PUT请求是类似的。
把id等于1的名称修改为小米至尊版
运行:
查看结果:
先来看最基本的match query:
NativeSearchQueryBuilder:Spring提供的一个查询条件构建器,帮助构建json格式的请求体
SearchHit包含以下信息:
SearchHits 包含以下信息:
利用NativeSearchQueryBuilder
可以方便的实现分页:
排序也通过NativeSearchQueryBuilder
完成:
桶就是分组,比如这里我们按照品牌brand进行分组:
显示的结果:
关键APIAggregationBuilders
:聚合的构建工厂类。所有聚合都由这个类来构建,看看他的静态方法:
@Test
public void testHighlight() {
//分词字段/高亮字段
String fieId = "name";
// 构建查询条件
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// match类型查询,会把查询条件进行分词,然后进行查询,多个词条之间是or的关系
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("手机电视至尊", fieId);
multiMatchQueryBuilder.type(MultiMatchQueryBuilder.Type.BEST_FIELDS);
multiMatchQueryBuilder.tieBreaker(0.3F);
//应该匹配的分词的最少数量
multiMatchQueryBuilder.minimumShouldMatch("30%");
queryBuilder.withQuery(multiMatchQueryBuilder);
// 排序
queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC));
//生成高亮查询器
HighlightBuilder highlightBuilder = new HighlightBuilder();
//高亮查询字段
highlightBuilder.field(fieId);
//如果要多个字段高亮,这项要为false
highlightBuilder.requireFieldMatch(false);
//高亮标签
highlightBuilder.preTags("");
highlightBuilder.postTags("");
queryBuilder.withHighlightBuilder(highlightBuilder);
// 执行搜索,获取结果
SearchHits search = elasticsearchRestTemplate.search(queryBuilder.build(), Product.class);
for (SearchHit hit : search.getSearchHits()) {
Product content = hit.getContent();
List name = hit.getHighlightField(fieId);
System.out.println(name);
StringBuilder stringBuilder = new StringBuilder();
for (String text : name) {
stringBuilder.append(text);
}
content.setName(stringBuilder.toString());
}
//当前页数据
search.getSearchHits().forEach(System.out::println);
}
才疏学浅,难免会有纰漏,如果你发现了错误的地方,可以在留言区提出来,我对其加以修改。
感谢您的阅读