效果丑,也就那么意思一下;因为sping boot已经集成了es,所以接入es只需要很简单的配置一下就好了。当然事先得下载好es,我用的是windows 6.5.3版本,没有遇到什么版本冲突问题,至于安装es和建立spring boot项目我就不细说了。
org.springframework.boot
spring-boot-starter-data-elasticsearch
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-thymeleaf
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.2
org.springframework.boot
spring-boot-starter-test
test
mysql
mysql-connector-java
runtime
com.alibaba
fastjson
1.2.54
org.springframework.boot
spring-boot-devtools
true
true
引入需要的jar包就好
spring:
datasource:
hikari:
jdbc-url: jdbc:mysql://url:port/database
username: username
password: password
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://url:port/database
username: username
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
thymeleaf:
cache: false
prefix: classpath:templates/
suffix: .html
mode: HTML
encoding: UTF-8
data:
elasticsearch:
cluster-name: es-test
cluster-nodes: localhost:9300
repositories:
enabled: true
main:
allow-bean-definition-overriding: true
server:
port: 80
mybatis:
type-aliases-package: com.xxx.xxx.xxx
cluster-name就是自己设置的es集群名称,可以在es安装目录下面的config/elasticsearch.yml配置
package com.xxx.xxx.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import java.util.Date;
@Document(indexName = "test", type = "company")
public class Company {
@Id
private String id;
@Field(analyzer = "ik",searchAnalyzer = "ik",store = true,type = FieldType.Text)
private String cname;
private String ename;
private String iname;
private String scode;
private String amt;
private String person;
@Field
private Date btime;
@Field
private Date sbtime;
@Field
private Date ptime;
private String address;
private String tel;
private String fax;
private String web;
private String email;
private String sec;
@Field(analyzer = "ik",searchAnalyzer = "ik",store = true,type = FieldType.Text)
private String industry;
private String business;
private String recommend;
private String over;
private Date ctime;
@Field(analyzer = "ik",searchAnalyzer = "ik",store = true,type = FieldType.Text)
private String industry2;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id == null ? null : id.trim();
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname == null ? null : cname.trim();
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename == null ? null : ename.trim();
}
public String getIname() {
return iname;
}
public void setIname(String iname) {
this.iname = iname == null ? null : iname.trim();
}
public String getScode() {
return scode;
}
public void setScode(String scode) {
this.scode = scode == null ? null : scode.trim();
}
public String getAmt() {
return amt;
}
public void setAmt(String amt) {
this.amt = amt == null ? null : amt.trim();
}
public String getPerson() {
return person;
}
public void setPerson(String person) {
this.person = person == null ? null : person.trim();
}
public Date getBtime() {
return btime;
}
public void setBtime(Date btime) {
this.btime = btime;
}
public Date getSbtime() {
return sbtime;
}
public void setSbtime(Date sbtime) {
this.sbtime = sbtime;
}
public Date getPtime() {
return ptime;
}
public void setPtime(Date ptime) {
this.ptime = ptime;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address == null ? null : address.trim();
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel == null ? null : tel.trim();
}
public String getFax() {
return fax;
}
public void setFax(String fax) {
this.fax = fax == null ? null : fax.trim();
}
public String getWeb() {
return web;
}
public void setWeb(String web) {
this.web = web == null ? null : web.trim();
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email == null ? null : email.trim();
}
public String getSec() {
return sec;
}
public void setSec(String sec) {
this.sec = sec == null ? null : sec.trim();
}
public String getIndustry() {
return industry;
}
public void setIndustry(String industry) {
this.industry = industry == null ? null : industry.trim();
}
public String getBusiness() {
return business;
}
public void setBusiness(String business) {
this.business = business == null ? null : business.trim();
}
public String getRecommend() {
return recommend;
}
public void setRecommend(String recommend) {
this.recommend = recommend == null ? null : recommend.trim();
}
public String getOver() {
return over;
}
public void setOver(String over) {
this.over = over == null ? null : over.trim();
}
public Date getCtime() {
return ctime;
}
public void setCtime(Date ctime) {
this.ctime = ctime;
}
public String getIndustry2() {
return industry2;
}
public void setIndustry2(String industry2) {
this.industry2 = industry2 == null ? null : industry2.trim();
}
}
@Id注解就是插入到es中当id的字段,@Field表明你想要查询的字段,中文字段用到ik分词器,如果不想被解析可以设置type=FieldType.Keyword。我的数据是同事从网上扒下来的,所以字段看上去有点奇怪,另外这实体类是用mybatis generator逆向生成的。
package com.xxx.xxx.mapper;
import com.jyw.es.model.Company;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
/**
* @author jiangyw
* @date 2019/1/22 10:17
*/
public interface ICompanyRepository extends ElasticsearchRepository {
}
这就是crud操作的接口,可以自定义一些方法,类似于mybatis的mapper接口
package com.xxx.xxx.controller;
import com.alibaba.fastjson.JSONObject;
import com.jyw.es.model.Company;
import com.jyw.es.service.ICompany;
import com.jyw.es.mapper.ICompanyRepository;
import org.apache.lucene.document.Field;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* @author jiangyw
* @date 2019/1/18 20:02
*/
@RestController
@RequestMapping("company")
public class CompanyController {
@Resource
private ICompany companyService;
@Resource
private ICompanyRepository companyRepository;
@Resource
private ElasticsearchTemplate elasticsearchTemplate;
@GetMapping("all")
public String all() {
List list = companyService.listAll();
return JSONObject.toJSONString(list);
}
/**
* 把数据库里的数据导入es中
*/
@GetMapping("save")
public String save() {
List list = companyService.listAll();
Iterable companies = companyRepository.saveAll(list);
return JSONObject.toJSONString(companies);
}
/**
* 搜索
*
* @param keyword keyword
*/
@PostMapping("search")
public String search(@RequestParam("keyword") String keyword) {
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
queryBuilder.should(QueryBuilders.matchQuery("cname", keyword));
queryBuilder.should(QueryBuilders.matchQuery("industry", keyword));
queryBuilder.should(QueryBuilders.matchQuery("industry2", keyword));
Pageable pageable = PageRequest.of(0, 10);
Iterable companies = companyRepository.search(queryBuilder, pageable);
return JSONObject.toJSONString(companies);
}
/**
* 搜索(高亮)
*
* @param keyword keyword
*/
@PostMapping("hsearch")
public String hSearch(@RequestParam("keyword") String keyword) {
Pageable pageable = PageRequest.of(0, 10);
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
queryBuilder.should(QueryBuilders.matchQuery("cname", keyword));
queryBuilder.should(QueryBuilders.matchQuery("industry", keyword));
queryBuilder.should(QueryBuilders.matchQuery("industry2", keyword));
String preTag = "";
String postTag = "";
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(queryBuilder)
.withHighlightFields(new HighlightBuilder.Field("cname").preTags(preTag).postTags(postTag),
new HighlightBuilder.Field("industry").preTags(preTag).postTags(postTag),
new HighlightBuilder.Field("industry2").preTags(preTag).postTags(postTag)
)
.withPageable(pageable)
.build();
AggregatedPage companies = elasticsearchTemplate.queryForPage(searchQuery, Company.class, new SearchResultMapper() {
@Override
public AggregatedPage mapResults(SearchResponse response, Class clazz, Pageable pageable) {
List list = new ArrayList<>();
for (SearchHit hit : response.getHits()) {
Company company = new Company();
HighlightField cname = hit.getHighlightFields().get("cname");
if (cname != null) {
company.setCname(cname.getFragments()[0].string());
}else {
company.setCname(hit.getSourceAsMap().get("cname").toString());
}
HighlightField industry = hit.getHighlightFields().get("industry");
if (industry != null) {
company.setIndustry(industry.getFragments()[0].toString());
}else {
company.setCname(hit.getSourceAsMap().get("industry").toString());
}
HighlightField industry2 = hit.getHighlightFields().get("industry2");
if (industry2 != null) {
company.setIndustry2(industry2.getFragments()[0].toString());
}else {
company.setCname(hit.getSourceAsMap().get("industry2").toString());
}
list.add(company);
}
return new AggregatedPageImpl<>((List) list);
}
});
return JSONObject.toJSONString(companies);
}
}
就这几个简单的接口……先调用一下save接口,把MySQL数据中的数据存入es,可以用kibana查看数据:
可以看到数据已经成功导入了
Title
这里我并没有用到Thymeleaf模板,就是普通的前端html;所以服务端要设置一下,允许跨域请求。
package com.xxx.xxx.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
/**
* 允许跨域
*
* @author jiangyw
* @date 2019/1/22 15:25
*/
@Configuration
public class MyConfig {
@Bean
public CorsFilter config() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
source.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(source);
}
}
{
"content": [
{
"cname": "无锡易通精密机械股份有限公司",
"industry": "普通机械制造行业",
"industry2": "普通机械制造行业"
},
{
"cname": "上海首达包装机械材料股份有限公司",
"industry": "机械行业",
"industry2": "机械行业"
},
{
"cname": "上海恒浥智能科技股份有限公司",
"industry": "其他通用机械",
"industry2": "其他通用机械业"
},
{
"cname": "上海狮虎能源科技股份有限公司",
"industry": "普通机械制造业",
"industry2": "普通机械制造业"
},
{
"cname": "上海大椿建筑机械股份有限公司",
"industry": "其他专用机械(行业代码 260207)",
"industry2": "其他专用机械"
},
{
"cname": "上海隆友精密刀具股份有限公司",
"industry": "机械制造",
"industry2": "机械制造业"
},
{
"cname": "上海申雁制冷设备股份有限公司",
"industry": "机械设备",
"industry2": "机械设备业"
},
{
"cname": "积康螺杆制造(上海)股份有限公司",
"industry": "机械基础件",
"industry2": "机械基础件"
},
{
"cname": "上海明索重型机械股份有限公司",
"industry": "机床工具行业",
"industry2": "机床工具行业"
},
{
"cname": "上海裕强户外用品股份有限公司",
"industry": "机械制造行业",
"industry2": "机械制造行业"
}
],
"empty": false,
"facets": [
],
"first": true,
"last": true,
"maxScore": 0.0,
"number": 0,
"numberOfElements": 10,
"pageable": "INSTANCE",
"size": 0,
"sort": {
"empty": true,
"sorted": false,
"unsorted": true
},
"totalElements": 10,
"totalPages": 1
}
可以看到通过高亮搜索得到的结果中,关键词已经被套上接口中设定好的标签
就是在项目中把MySQL中的数据导入es,然后通过es分词、高亮搜索;由于spring boot已经集成好了,所以并不需要我们做多少事情……