文章目录
Spring Data Elasticsearch 简介
SpringData项目下的子项目 用于访问Elasticsearch
Spring Data Elasticsearch常用注解
@Document
指定实体类和索引对应关系s
属性:
indexName
:索引名称shards
: 主分片数量。从ES 7开始默认1replicas
:复制分片数量。从ES 7开始默认1
@Id
指定主键
@Field
指定普通属性
属性:
-
name
:字段类型。默认为当前属性名 -
type
: 对应Elasticsearch中属性类型,默认是FieldType.Auto -
analyzer
: 分词器名称,必须type=Text才有效。默认为standard -
index
: 是否创建索引。默认true
代码示例
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(indexName = "item_index", shards = 1, replicas = 0)
public class Item implements Serializable {
/**
* @Id Spring Data 框架的通用注解,用于描述一个主键属性
* 在Spring Data Elasticsearch 框架中,读写操作id字段的首,会在_source中记录同值数据
*
* @Field 描述属性和索引字段映射
* - name 字段类型。默认为当前属性名
* - type 字段类型。默认是FieldType.Auto
* - analyzer 分词器名称,必须type=Text才有效。默认为standard
* - index 是否创建索引。默认true
*/
@Id
@Field(name = "id", type = FieldType.Keyword)
private String id;//商品id
@Field(name = "title", type = FieldType.Text, analyzer = "ik_max_word")
private String title;//商品标题
@Field(name = "item_desc", type = FieldType.Text, analyzer = "ik_smart")
private String itemDesc;//商品描述
@Field(name = "sellPoint", type = FieldType.Text, analyzer = "ik_smart")
private String sellPoint; //商品卖点
@Field(name = "price", type = FieldType.Long)
private Long price;//价格
@Field(name = "num", type = FieldType.Integer, index = false)
private int num;/*库存*/
}
Spring Data Elasticsearch配置文件
# 支持集群化配置。多个节点的地址用逗号分隔
spring:
elasticsearch:
rest:
uris: http://192.168.190.128:9200 # 集群节点路径
# data:
# elasticsearch:
# cluster-name: xxx # 集群名称
# cluster-nodes: 192.168.137.128:9300,ip:9300
Spring Data Elasticsearch访问示例
@Autowired
private ElasticsearchRestTemplate template;
创建索引
/**
* 创建索引
* PUT my_first_index
* 创建索引并映射
* PUT my_first_index2
* { "mappings": {"properties": {
* "id":{"type":"long","index":"true"},
* "title":{"type":"text","index":"true","analyzer":"ik_max_word" }
* }
* }
*/
@Test
public void createIndex() {
//获取索引操作对象
IndexOperations indexOps = template.indexOps(Item.class);
//创建索引
boolean isCreated = indexOps.create();
System.out.println(isCreated ? "创建成功" : "创建失败");
/*创建映射 */
boolean isMapped = indexOps.putMapping(indexOps.createMapping());
System.out.println(isMapped ? "映射配置成功" : "映射配置失败");
}
删除索引
/**
* 删除索引
* 对应: DELETE /my_first_index2
*/
@Test
public void deleteIndex() {
boolean isDeleted = template.indexOps(Item.class).delete();
System.out.println(isDeleted ? "删除成功" : "删除失败");
}
添加数据
/**
* 新增文档
* 对应:
* POST test_search/_bulk
* { "index": {}}
* { "dname" : "Sales Department", "ename" : "张三", "eage":20, "hiredate" : "2019-01-01", "gender" : "男性" }
* { "index": {}}
* { "dname" : "Sales Department", "ename" : "李四", "eage":21, "hiredate" : "2019-02-01", "gender" : "男性"
* <p>
* 全量替换使用save()方法
*/
@Test
public void insertDoc() {
Item item1 = new Item("001", "华为P40", "照相机很牛,价格有点贵",
"国产高端机", 489900L, 100);
Item item2 = new Item("002", "荣耀Play 3T", "玩游戏的手机,扩展配置为0,就是RAM大",
"很便宜", 119900L, 100);
Item item3 = new Item("003", "红米5", "冬天不怕冷,暖手暖脚神器,容易爆炸",
"国产网红产品1号", 289900L, 100);
Item item4 = new Item("004", "IPhone 12", "贵,曾经很贵",
"品牌象征", 689900L, 100);
Item item5 = new Item("005", "华为P30", "照相机很牛,价格有点贵",
"国产中端机", 389900L, 100);
Item item6 = new Item("006", "荣耀Play", "玩游戏的手机,扩展配置为0,就是RAM大",
"很便宜", 119900L, 100);
Item item7 = new Item("007", "红米4", "冬天不怕冷,暖手暖脚神器,容易爆炸",
"国产网红产品1号", 189900L, 100);
Item item8 = new Item("008", "IPhone 11", "贵,曾经很贵",
"品牌象征", 589900L, 100);
template.save(item1);
template.save(item2, item3, item4, item5, item6, item7, item8);
System.out.println("添加数据结束");
}
修改数据
/**
* 修改数据
* 对应: POST my_first_index/_update/4
* {"doc":{"name":"赵六"}}
*/
@Test
public void updateDoC() {
UpdateQuery updateQuery = UpdateQuery.builder("001")
.withDocument(Document.create().append("num", 200))
.build();
UpdateResponse updateResponse =
template.update(updateQuery, IndexCoordinates.of("item_index"));
System.out.println(updateResponse.getResult());
}
删除数据
/**
* 删除
* 对应: DELETE my_first_index/_doc/3
*/
@Test
public void deleteDoc() {
/*Item item = new Item("009", "IPhone 11", "贵,曾经很贵",
"品牌象征", 589900L, 100);
template.save(item);*/
String delete = template.delete("009", Item.class);
System.out.println(delete);
}
查询数据
/**
* 主键查询
* 对应: GET my_first_index/_doc/1
*/
@Test
public void searchById() {
Item item = template.get("001", Item.class);
System.out.println(item);
}
/**
* 全字段查询
* 对应: GET /索引/_search?q=xxx
* <p>
* NativeSearchQuery - spring data elasticsearch提供的一个查询对象
* NativeSearchQueryBuilder - 是NativeSearchQuery类型的构建器。
* - withQuery(QueryBuilder queryBuilder) - 提供搜索条件
* - build() - 构建一个NativeSearchQuery类型的对象。
* <p>
* QueryBuilder - Elasticsearch Java 客户端API提供的搜索条件类型
* 有若干实现类型。对应不同的搜索方案。实现类型的命名有一定的规则,和搜索方案相关。
* 如:query string搜索。 对应的实现是QueryStringQueryBuilder
* DSL中的match搜索。 对应的实现是MatchQueryBuilder
*/
@Test
public void searchQueryString() {
NativeSearchQuery query =
new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.queryStringQuery("贵"))
.build();
SearchHits<Item> searchHits = template.search(query, Item.class);
System.out.println("是否有查询结果 :" + searchHits.isEmpty());
System.out.println("数据条数 :" + searchHits.getTotalHits());
System.out.println("最大相关度分数 max_score :" + searchHits.getMaxScore());
searchHits.forEach(hit -> {
System.out.println(hit.getContent());
});
}
/**
* math_all 查询所有数据
* 对应: GET test_search/_search
* {"query" : { "match_all" : {} }}
*/
@Test
public void mathAll() {
SearchHits<Item> searchHits = template.search(
new NativeSearchQueryBuilder().withQuery(QueryBuilders.matchAllQuery()).build()
, Item.class
);
searchHits.forEach(hit -> {
System.out.println(hit.getContent());
});
}
/**
* match
* GET test_search/_search
* {"query":{ "match":{"dname":"Sales"} } }
*/
@Test
public void match() {
SearchHits<Item> searchHits =
template.search(
new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchQuery("item_desc", "照相机很牛,价格挺贵")).build(),
Item.class
);
searchHits.forEach(hit -> {
System.out.println(hit.getContent());
});
}
/**
* match_phrase
* GET item_index/_search
* { "query": {"match_phrase": {"item_desc": "价格"}}}
*/
@Test
public void matchPhrase() {
SearchHits<Item> searchHits =
template.search(
new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchPhraseQuery("item_desc", "价格")).build(),
Item.class
);
searchHits.forEach(hit -> {
System.out.println(hit.getContent());
});
}
/**
* range
*/
@Test
public void matchAll() {
SearchHits<Item> searchHits =
template.search(
new NativeSearchQueryBuilder().
withQuery(QueryBuilders.rangeQuery("price")
.gte(200000L)
.lte(500000L))
.build(),
Item.class
);
searchHits.forEach(hit -> {
System.out.println(hit.getContent());
});
}
@Test
public void boolS() {
/*
* BoolQueryBuilder中包含3个集合。分别是:
* List<QueryBuilder> must
* List<QueryBuilder> mustNot
* List<QueryBuilder> should
* 提供了3个获取结合的方法
* must()
* mustNot()
* should()
* 提供了3个直接向指定集合中保存QueryBuilder对象的方法
* must(QueryBuilder b) { must().add(b); }
* mustNot(QueryBuilder)
* should(QueryBuilder)
*/
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
queryBuilder.must(QueryBuilders.rangeQuery("price").lte(500000L));
queryBuilder.must(QueryBuilders.matchQuery("title", "华为"));
NativeSearchQuery query = new NativeSearchQueryBuilder().withQuery(queryBuilder).build();
SearchHits<Item> searchHits = template.search(query, Item.class);
searchHits.forEach(hit -> {
System.out.println(hit.getContent());
});
}
分页和排序
/**
* 排序和分页
*/
@Test
public void sortAndPageable() {
SearchHits<Item> searchHits = template.search(
new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchAllQuery())
.withPageable(
PageRequest.of(0, 3,
Sort.by(Sort.Order.asc("price"), Sort.Order.desc("id"))
//Sort.by(Sort.Direction.ASC, "price")
)
).build()
, Item.class
);
searchHits.forEach(hit -> {
System.out.println(hit.getContent());
});
}
高亮数据
/**
* 高亮
*/
@Test
public void highlight() {
//创建高亮字段
HighlightBuilder.Field field1 = new HighlightBuilder.Field("title");
field1.numOfFragments(1);
field1.fragmentSize(3);
//高亮前缀
field1.preTags("<span style='color:red'>");
//高亮后缀
field1.postTags("</span>");
NativeSearchQuery query =
new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchQuery("title", "华为"))
.withHighlightFields(field1) // 设置若干高亮字段
.build();
SearchHits<Item> searchHits = template.search(query, Item.class);
List<Item> itemList = new ArrayList<>();
searchHits.forEach(hit -> {
Item item = hit.getContent();
List<String> highlight = hit.getHighlightField("title");
if (null != highlight && highlight.size() > 0) {
item.setTitle(highlight.get(0));
}
itemList.add(item);
});
itemList.forEach(System.out::println);
}
@Test
public void highlight2() {
NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(QueryBuilders.matchQuery("title", "华为"));
//排序
nativeSearchQuery.addSort(Sort.by(Sort.Direction.DESC, "price"));
//分页
nativeSearchQuery.setPageable(PageRequest.of(0, 2));
//设置高亮
HighlightBuilder highlightBuilder = new HighlightBuilder();
//设置高亮属性
highlightBuilder.field("title");//.numOfFragments(2).fragmentSize(3);
//高亮前缀
highlightBuilder.preTags("<span style='color:red'>");
// 高亮内容后缀
highlightBuilder.postTags("</span>");
//高亮查询
HighlightQuery highlightQuery = new HighlightQuery(highlightBuilder);
//应用高亮
nativeSearchQuery.setHighlightQuery(highlightQuery);
SearchHits<Item> searchHits = template.search(nativeSearchQuery, Item.class);
List<SearchHit<Item>> highlights = searchHits.getSearchHits();
List<Item> itemList = new ArrayList<>();
highlights.forEach(hit -> {
Item item = hit.getContent();
String title = hit.getHighlightField("title").get(0);
item.setTitle(title);
itemList.add(item);
});
itemList.forEach(System.out::println);
}
}
Spring Data Elasticsearch依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
</dependencies>