1.导入Maven依赖
<!--Elasticsearch相关依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
指定ES版本
<properties>
<java.version>1.8</java.version>
<elasticsearch.version>7.6.2</elasticsearch.version>
</properties>
2.配置ElastciSearch
@Configuration
public class ElasticSearchConfig {
@Bean(destroyMethod = "close")
public RestHighLevelClient restClient() {
ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo("110.40.***.**:9200")
.build();
RestHighLevelClient client = RestClients.create(clientConfiguration).rest();
return client;
}
@Bean
public SearchRequest searchRequest() {
//指定搜索时的文档
return new SearchRequest("pms");
}
}
3.配置application.yml
server:
port: 8810
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
username: root
password: 123456
url: jdbc:mysql://110.11.11.11:3306/mall?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
data:
elasticsearch:
repositories:
enabled: true
client:
reactive: #单机节点名称
endpoints: docker-cluster
elasticsearch:
rest: #连接URL
uris: http://110.40.242.86:9200
mybatis:
mapper-locations: classpath:mapper/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
logging:
level:# 打印ElasticSearch的执行语句
org.springframework.data.elasticsearch.client.WIRE: TRACE
4.创建需要生成的文档对象
@Data
@Document(indexName = "pms")
public class EsProductDTO implements Serializable {
private static final long serialVersionUID = -1L;
@Id
private Long id;
@Field(type = FieldType.Keyword)
private String productSn;
private Long brandId;
@Field(type = FieldType.Keyword)
private String brandName;
private Long productCategoryId;
@Field(type = FieldType.Keyword)
private String productCategoryName;
private String pic;
//中文ik分词词
@Field(analyzer = "ik_max_word",type = FieldType.Text)
private String name;
@Field(analyzer = "ik_max_word",type = FieldType.Text)
private String subTitle;
@Field(analyzer = "ik_max_word",type = FieldType.Text)
private String keywords;
private BigDecimal price;
private Integer sale;
private Integer newStatus;
private Integer recommandStatus;
private Integer stock;
private Integer promotionType;
private Integer sort;
@Field(type =FieldType.Nested)
private List<EsProductAttributeValue> attrValueList;
}
@Data
public class EsProductAttributeValue implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private Long productAttributeId;
//属性值
@Field(type = FieldType.Keyword)
private String value;
//属性参数:0->规格;1->参数
private Integer type;
//属性名称
@Field(type=FieldType.Keyword)
private String name;
}
5.创建Mapper
Mapper.java
public interface EsProductMapper {
List<EsProductDTO> getAllEsProductList(Long id);
}
Mapper.xml 一对多关系
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.liu.elasticsearch.mapper.EsProductMapper">
<resultMap id="EsProductDto" type="com.liu.elasticsearch.dto.EsProductDTO">
<id column="id" property="id"/>
<result column="product_sn" property="productSn"/>
<result column="brand_id" property="brandId"/>
<result column="brand_name" property="brandName"/>
<result column="product_category_id" property="productCategoryId"/>
<result column="product_category_name" property="productCategoryName"/>
<result column="pic" property="pic"/>
<result column="name" property="name"/>
<result column="sub_title" property="subTitle"/>
<result column="price" property="price"/>
<result column="sale" property="sale"/>
<result column="new_status" property="newStatus"/>
<result column="recommand_status" property="recommandStatus"/>
<result column="stock" property="stock"/>
<result column="promotion_type" property="promotionType"/>
<result column="sort" property="sort"/>
<collection property="attrValueList" javaType="ArrayList" ofType="com.liu.elasticsearch.dto.EsProductAttributeValue" select="getEsProductAttributeValue" column="id"/>
</resultMap>
<resultMap id="EsProductAttributeValue" type="com.liu.elasticsearch.dto.EsProductAttributeValue">
<result column="id" property="id"/>
<result column="product_attribute_id" property="productAttributeId"/>
<result column="value" property="value"/>
<result column="type" property="type"/>
<result column="name" property="name"/>
</resultMap>
<select id="getAllEsProductList" resultMap="EsProductDto">
select id,
product_sn,
brand_id,
brand_name,
product_category_id,
product_category_name,
pic,
name,
sub_title,
price,
sale,
new_status,
recommand_status,
stock,
promotion_type,
sort
from pms_product
<if test="id">
where id=#{id}
</if>
</select>
<select id="getEsProductAttributeValue" resultMap="EsProductAttributeValue">
select pms_product_attribute_value.id
product_attribute_id,
value,
type,
name
from pms_product_attribute_value,pms_product_attribute where product_id=#{id} and product_attribute_id=pms_product_attribute.id;
</select>
</mapper>
6.Service层做ElasticSearch操作
@Service
@RequestMapping("/es")
public class EsProductServiceImpl {
@Autowired
EsProductMapper productMapper;
@Autowired
EsProductRepository productRepository;
@Autowired
SearchRequest searchRequest;
@Autowired
RestHighLevelClient client;
/**
* 从数据库中导入所有商品到ES
*/
@GetMapping("/importAll")
@ResponseBody
public int importAll(){
List<EsProductDTO> allEsProductList = productMapper.getAllEsProductList(null);
Iterable<EsProductDTO> productDTOIterable = productRepository.saveAll(allEsProductList);
Iterator<EsProductDTO> iterator = productDTOIterable.iterator();
int resultCount=0;
while(iterator.hasNext()){
resultCount++;
iterator.next();
}
return resultCount;
}
/**
* 根据id删除商品
*/
public void delete(Long id) {
productRepository.deleteById(id);
}
/**
* 批量删除商品
*/
public void delete(List<Long> ids){
if (!CollectionUtils.isEmpty(ids)) {
List<EsProductDTO> esProductList = new ArrayList<>();
for (Long id : ids) {
EsProductDTO esProduct = new EsProductDTO();
esProduct.setId(id);
esProductList.add(esProduct);
}
productRepository.deleteAll(esProductList);
}
}
/**
* 根据关键字搜索标题
*/
@GetMapping("/search")
@ResponseBody
public List<EsProductDTO> search(String keyword, Integer pageNum, Integer pageSize) throws IOException {
keyword="小米";
//查询条件
SearchSourceBuilder requestBuilder=new SearchSourceBuilder();
MatchQueryBuilder matchQuery = QueryBuilders.matchQuery("subTitle", keyword);
requestBuilder.query(matchQuery);
//查询名字高亮显示
HighlightBuilder highlightBuilder=new HighlightBuilder();
highlightBuilder.field("subTitle");
highlightBuilder.requireFieldMatch(false);
highlightBuilder.preTags("<span style='color:red'>");
highlightBuilder.postTags("</span>");
requestBuilder.highlighter(highlightBuilder);
searchRequest.source(requestBuilder);
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHit[] hits = search.getHits().getHits();
List<EsProductDTO> productDTOList=new ArrayList<>();
for (SearchHit hit : search.getHits().getHits()) {
//解析高亮字段
Map<String, HighlightField> highlightFieldMap= hit.getHighlightFields();
HighlightField subTitle = highlightFieldMap.get("subTitle");
Map<String,Object> sourceMap= hit.getSourceAsMap();//原来的结果
//结果转换为对象
EsProductDTO productDTO = JSON.parseObject(JSON.toJSONString(sourceMap), EsProductDTO.class);
//解析高亮字段,将原来字段替换为高亮字段
if (subTitle!=null){
Text[] fragments = subTitle.fragments();
StringBuilder n_username= new StringBuilder();
for (Text text : fragments) {
n_username.append(text);
}
sourceMap.put("subTitle", n_username.toString());
}
//修改过高亮的字段存入List
productDTOList.add(productDTO);
}
return productDTOList;
}
}
常用API
/**
* com.liuy.lmall.LmallApplicationTest
*
* @author liuy
* @data 2021/9/23 10:19
**/
@SpringBootTest
public class LmallApplicationTest {
@Autowired
@Qualifier("restHighLevelClient")
private RestHighLevelClient client;
@Test
void testCreateIndex() throws IOException {
//创建索引请求
CreateIndexRequest request=new CreateIndexRequest("mall_index");
//执行请求IndicesClient
CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
System.out.println(createIndexResponse);
}
//索引所否存在
@Test
void testExistIndex() throws IOException {
GetIndexRequest request=new GetIndexRequest("mall_index");
boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
System.out.println(exists);
}
//删除索引
@Test
void testdeleteIndex() throws IOException {
DeleteIndexRequest request=new DeleteIndexRequest("mall_index");
//删除
AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);
System.out.println(delete.isAcknowledged());
}
//添加文档
@Test
void testAddDocument() throws IOException {
UmsAdmin admin=new UmsAdmin("liuyt","123465");
//创建请求
IndexRequest request=new IndexRequest("mall_index");
//规则 put /mall_index/_doc/1
request.id("1");
request.timeout(TimeValue.timeValueSeconds(1));
request.timeout("1s");
//数据放入请求 json
request.source(JSONUtil.parse(admin), XContentType.JSON);
//发送请求,获取响应结果
IndexResponse index = client.index(request, RequestOptions.DEFAULT);
System.out.println(index.toString());
System.out.println(index.status());
}
//获取文档,判断是否存在get /index/doc/1
@Test
void testIsExist() throws IOException {
GetRequest getRequest=new GetRequest("mall_index","1");
//不获取返回的_source 的上下文 性能更快
getRequest.fetchSourceContext(new FetchSourceContext(false));
getRequest.storedFields("_none_");
boolean exists = client.exists(getRequest, RequestOptions.DEFAULT);
System.out.println(exists);
}
//获取文档信息
@Test
void testGetDocument() throws IOException {
GetRequest getRequest=new GetRequest("mall_index","1");
GetResponse documentFields = client.get(getRequest, RequestOptions.DEFAULT);
System.out.println(documentFields.getSourceAsString());
System.out.println(documentFields);
}
//更新文档信息
@Test
void testUpdateDocument() throws IOException {
UpdateRequest updateRequest=new UpdateRequest("mall_index","1");
updateRequest.timeout("1s");
UmsAdmin admin=new UmsAdmin("liuyt","abcdefz");
updateRequest.doc(JSON.toJSONString(admin),XContentType.JSON);
UpdateResponse update = client.update(updateRequest, RequestOptions.DEFAULT);
System.out.println(update.status());
System.out.println(update);
}
//删除文档信息
@Test
void testDeleteDocument() throws IOException {
DeleteRequest deleteRequest=new DeleteRequest("mall_index","1");
deleteRequest.timeout("1s");
DeleteResponse delete = client.delete(deleteRequest, RequestOptions.DEFAULT);
System.out.println(delete.status());
System.out.println(delete);
}
//批量导入数据
@Test
void testBlukRequest () throws IOException {
//创建批处理请求
BulkRequest bulkRequest=new BulkRequest();
bulkRequest.timeout("10s");
ArrayList<UmsAdmin> users=new ArrayList<>();
users.add(new UmsAdmin("123"));
users.add(new UmsAdmin("1231"));
users.add(new UmsAdmin("1232"));
users.add(new UmsAdmin("12"));
users.add(new UmsAdmin("1233"));
users.add(new UmsAdmin("1234"));
users.add(new UmsAdmin("12345"));
//批量处理请求
for (int i = 0; i < users.size(); i++) {
//批量添加
bulkRequest.add(
new IndexRequest("mall_index")
.id(""+(i+1))
.source(JSON.toJSONString(users.get(i)),XContentType.JSON)
);
}
//是否失败
BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);
System.out.println(bulk.hasFailures());
}
@Test
void testSearch() throws Exception{
SearchRequest searchRequest=new SearchRequest("mall_index");
//构建搜索条件
SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();
//匹配查询QueryBuilders.matchQuery("username","12");
//精确查询QueryBuilders.termQuery("username","12");
//查询匹配模式
MatchQueryBuilder queryBuilder= QueryBuilders.matchQuery("username","12");
searchSourceBuilder.query(queryBuilder);
searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
//高亮
HighlightBuilder highlightBuilder=new HighlightBuilder();
highlightBuilder.field("username");
highlightBuilder.requireFieldMatch(false);// 关闭多个高亮显示
highlightBuilder.preTags("<span style='color:red'>");
highlightBuilder.postTags("</span>");
searchSourceBuilder.highlighter(highlightBuilder);
//执行搜索
searchRequest.source(searchSourceBuilder);
SearchResponse search = client.search(searchRequest,RequestOptions.DEFAULT);
//解析结果
System.out.println(JSON.toJSONString(search.getHits()));
for (SearchHit hit : search.getHits().getHits()) {
//解析高亮字段
Map<String, HighlightField> highlightFieldMap= hit.getHighlightFields();
HighlightField username = highlightFieldMap.get("username");
Map<String,Object> sourceMap= hit.getSourceAsMap();//原来的结果
//解析高亮字段,将原来字段替换为高亮字段
if (username!=null){
Text[] fragments = username.fragments();
String n_username="";
for (Text text : fragments) {
n_username+=text;
}
sourceMap.put("username",n_username);
}
System.out.println(hit.getSourceAsMap());
}
}
}