这篇文章同样可以在我自搭的小博客里看到:https://spzgczyj.top/blog/article.html?articleId=310
准备环节
第一步:在pom.xml中引入elasticsearch的依赖
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>${elasticsearch.version}</version>
</dependency>
<!--elasticsearch依赖log4j,这里版本需要小于等于2.7-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.7</version>
</dependency>
第二步:覆盖springboot给我们提供的默认版本的es,我这里用的es是6.3.2,所以这里的es版本我指定成6.3.2
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!--覆盖springboot默认版本的elasticsearch-->
<elasticsearch.version>6.3.2</elasticsearch.version>
<!--<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>-->
</properties>
第三步:编写配置类:
package com.gkd.blog.config;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* @author :zhaoyijie(Aquarius_genius)水瓶座鬼才
* @create :2020/1/25 13:01
* @Email : 747897928@qq.com
*/
@Configuration
public class ESConfig {
@Bean
public TransportClient client() throws UnknownHostException {
TransportAddress node=new TransportAddress(InetAddress.getByName("localhost"),9300);
//集群名blog
Settings settings = Settings.builder().put("cluster.name","blog").build();
TransportClient client=new PreBuiltTransportClient(settings);
//这里可以addTransportAddress(node)多个节点
client.addTransportAddress(node);
System.out.println(client);
return client;
}
}
说明:不同版本的可能会不同:5.5.2版本用InetSocketTransportAddress,6.3.2版本用TransportAddress。这里端口用9300,ES Rest API端口9200,项目需要用tcp协议去和es通信 ,ES默认tcp端口9300,默认cluster-name my-application。这里要特别说明,实际开发不是这样子写的,因为这样子写配置文件需要改es的yml文件,详情看我的另外一篇文章:elasticsearch报错解决办法:NoNodeAvailableException[None of the configured nodes are available。但是我们只是简单实现,简单写也是可以的,因为我们的目的就一个,快速查询出匹配的文章就行了,我这里做的是快速查询出匹配的文章。
第四步:编写实体类
package com.gkd.blog.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.lang.NonNull;
import java.util.Date;
/**
* @author :zhaoyijie(Aquarius_genius)水瓶座鬼才
* @create :2020/1/5 15:12
* @Email : 747897928@qq.com
*/
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Article {
private Integer id;//文章id
@NonNull
private String title;//文章标题
@NonNull
private String content;//文章内容
@NonNull
private String articleClassify;//文章类别
//写成long时间戳,避免ios里的js日期格式不兼容的情况发生
@JsonFormat(shape = JsonFormat.Shape.NUMBER)
private Date addTime;//文章加入时间
private Integer viewCount;//文章浏览量
private Integer sumComment;//总评论
private Integer supportCount;//总点赞数
}
第五步:编写控制器类
package com.gkd.blog.controller;
import com.gkd.blog.util.EsUtils;
import org.elasticsearch.client.transport.TransportClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author :zhaoyijie(Aquarius_genius)水瓶座鬼才
* @create :2020/1/25 13:27
* @Email : 747897928@qq.com
* @Description :
*/
@RestController
public class elasticsearchController {
@Autowired
TransportClient client;
/**
* @Description: 跟据关键字查找符合条件的数据,只跟文章标题,内容,文章分类比较
* @Param: [keyword] 查询关键字
* @return: org.springframework.http.ResponseEntity
*/
@PostMapping("query/blog/article")
@ResponseBody
public ResponseEntity query(@RequestParam(name = "keyword") String keyword){
StopWatch watch=new StopWatch();
watch.start();
Map<String, Object> map=new HashMap<>();
List<Map<String, Object>> result = EsUtils.queryShould(keyword, this.client);
watch.stop();
map.put("TotalTimeMillis",watch.getTotalTimeMillis());
map.put("result",result);
return new ResponseEntity(map, HttpStatus.OK);
}
}
第六步:编写ESutils类
package com.gkd.blog.util;
import com.gkd.blog.entity.Article;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import java.io.IOException;
import java.util.*;
/**
* @author :zhaoyijie(Aquarius_genius)水瓶座鬼才
* @create :2020/1/25 14:34
* @Email : 747897928@qq.com
* @Description :
*/
public class EsUtils {
public static List<Map<String, Object>> queryMust(Article article, TransportClient client) {
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//must想当于and should相当于or
boolQuery.must(QueryBuilders.matchQuery("title", article.getTitle()));
boolQuery.must(QueryBuilders.matchQuery("content", article.getContent()));
boolQuery.must(QueryBuilders.matchQuery("articleClassify", article.getArticleClassify()));
SearchRequestBuilder builder = client.prepareSearch("blog").
setTypes("article").
setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
.setQuery(boolQuery);
//System.out.println(builder);
SearchResponse searchResponse = builder.get();
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
for (SearchHit hit : searchResponse.getHits()) {
result.add(hit.getSourceAsMap());
}
return result;
}
public static List<Map<String, Object>> queryShould(String keyword, TransportClient client) {
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//must想当于and should相当于or
boolQuery.should(QueryBuilders.matchQuery("title", keyword));
boolQuery.should(QueryBuilders.matchQuery("content", keyword));
boolQuery.should(QueryBuilders.matchQuery("articleClassify", keyword));
SearchRequestBuilder builder = client.prepareSearch("blog").
setTypes("article").
setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
.setQuery(boolQuery);
//System.out.println(builder);
SearchResponse searchResponse = builder.get();
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
for (SearchHit hit : searchResponse.getHits()) {
result.add(hit.getSourceAsMap());
}
return result;
}
public static String add(String title, String content, String articleClassify,
Date date, TransportClient client) {
try {
XContentBuilder xContentBuilder = XContentFactory.
jsonBuilder().
startObject().
field("title", title).
field("content", content).
field("articleClassify", articleClassify).
field("data", date).
endObject();
IndexResponse result = client.prepareIndex("blog", "article").setSource(xContentBuilder).get();
return result.getId();
} catch (IOException e) {
e.printStackTrace();
return e.getMessage();
}
}
public static String delete(String id, TransportClient client) {
DeleteResponse deleteResponse = client.prepareDelete("blog", "article", id).get();
return deleteResponse.getResult().toString();
}
public static String update(String id, Article article, TransportClient client) {
UpdateRequest updateRequest = new UpdateRequest("blog", "article", id);
try {
XContentBuilder builder = XContentFactory.jsonBuilder().startObject();
builder.field("title", article.getTitle());
builder.field("content", article.getContent());
builder.field("articleClassify", article.getArticleClassify());
builder.field("data", article.getAddTime());
builder.endObject();
updateRequest.doc(builder);
UpdateResponse result = client.update(updateRequest).get();
return result.getResult().toString();
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
}
}
说明:虽然上面很多地方写死了,但是我们的需求就是查出索引为blog,type为article下,与搜索关键字匹配的文章,与文章的标题,内容,分类进行匹配,用should,相当于mysql里的or。再次说明一点,如果你要这样子写,你必须去改es里的一个配置文件,详情看我的另外一篇文章:elasticsearch报错解决办法:NoNodeAvailableException[None of the configured nodes are available至于同步嘛,就交给logstash去做,它会每分钟去查mysql然后更新es里的内容,但是这样子坏处也很多,因为一个es部署得1.3G,一个logstash部署得770mb,两个加起来就2G多的运行内存了,所以最后,我们的博客没办法加上es,因为租借的阿里云服务器就2G运行内存.....
最后看看效果,postman查看一下logstash同步后es里的全部数据:
我们通过接口查一下关键词为”恶龙“的文章:
看到TotaltimeMillis,这是我之前在java代码里插入了一个程序执行时间的计时器,看看,我们查询到数据仅仅只需要7ms,这个速度很惊人。
不过这个代码使用了默认的分词器standard,这个分词器会把中文分成一个个单词去匹配,这样子就会出现,你要你文章存在一个与关键字里一个中文字符匹配就会算匹配成功,就是说你本来想要查有关中国人的文章,结果有的文章并没有“中国人”这个词却有“中”或者“国”再或者有"人"这个词,就会算是匹配成功,这显然不是我们想要的结果。但是在这里不做分词器的介绍,如果感兴趣的小伙伴可以去github查看一下es的中文分词插件ik。
下载地址:https://github.com/medcl/elasticsearch-analysis-ik/releases?after=v6.4.2