一.项目包含的功能
1.高亮搜索;
2.词语自动补全;
3.分页查询;
4.复合查询;
5.对索引的增、删、改、查;
6.对文档的增、删、改;
7.搜索结果排序;
8.其他功能:文件读取(word、txt、pdf)
二.依赖环境版本
1.Elasticsearch 6.6.1;
2.jdk 1.8
3.前端分页插件:网上找的
4.elasticsearch-rest-high-level-client 6.6.1
5.spring boot 2.1.3
6.kibana 6.6.0
三.访问路径
1.项目路径:http://localhost:8080/searchTest.html
2.kibana路径:http://localhost:5601
3.Elasticsearch启动检测路径:http://localhost:9200/
四.页面效果
五.代码
1.bean实体类
package com.demo.elasticsearch.bean; import java.util.Date; /** * @Author: ln * @Date: 2019/2/26 08:59 * @Description: */ public class FileBean { //text支持分词搜索的字段有:name,author,content,filePath //keyword支持不分词搜索的字段有:name,author //suggest支持自动补全搜索的字段有:name,author /** 主键id */ private String id; /** 文件名称 */ private String name; /** 作者名称 */ private String author; /** 文件内容 */ private String content; /** 文件路径 */ private String filePath; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getFilePath() { return filePath; } public void setFilePath(String filePath) { this.filePath = filePath; } //不分词搜索 public String getKeywordName() { return this.name; } public String getKeywordAuthor() { return this.author; } //自动补全 public String getSuggestName() { return this.name; } public String getSuggestAuthor() { return this.author; } }
package com.demo.elasticsearch.bean; /** * @Author: ln * @Date: 2019/2/26 08:59 * @Description: */ public class FileBeanQuery { /** 文件名称 */ private String name; /** 作者名称 */ private String author; /** 文件内容 */ private String content; /** 文件路径 */ private String filePath; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getFilePath() { return filePath; } public void setFilePath(String filePath) { this.filePath = filePath; } }
2.controller控制层
package com.demo.elasticsearch.controller; import com.demo.elasticsearch.bean.FileBean; import com.demo.elasticsearch.bean.FileBeanQuery; import com.demo.elasticsearch.bean.FileMapping; import com.demo.elasticsearch.service.ElasticsearchService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.io.IOException; /** * @Author: ln * @Date: 2019/2/22 14:04 * @Description: elasticsearch demo */ @Controller @RequestMapping("/demo") public class ElasticsearchController { @Autowired private ElasticsearchService elasticsearchService; /* 创建索引 */ @RequestMapping("/createIndex") @ResponseBody public String createIndex(String index, FileMapping mapping) throws IOException { String result = elasticsearchService.createIndex(index, mapping); return result; } /* 删除索引 Elasticsearch的版本要与client的版本一致,spring的start版本6.4.3调试失败,6.6.1调试成功 */ @RequestMapping("/delIndex") @ResponseBody public String delIndex(String index) throws IOException { String result = elasticsearchService.delIndex(index); return result; } /* 新建文档(若索引不存在则新建) */ @RequestMapping("/putDocument") @ResponseBody public String putDocument(String index, FileBean fileBean) throws IOException { String result = elasticsearchService.putDocument(index, fileBean); return result; } /* 删除文档 */ @RequestMapping("/delDocument") @ResponseBody public String delDocument(String index, String id) throws IOException { String result = elasticsearchService.delDocument(index, id); return result; } /* 获取文档 */ @RequestMapping("/getDocument") @ResponseBody public String getDocument(String index, String id) throws IOException { String result = elasticsearchService.getDocument(index, id); return result; } /* 全局搜索 */ @RequestMapping("/keywordSearch") @ResponseBody public String keywordSearch(String index, String value, int current, int size) throws IOException { String result = elasticsearchService.keywordSearch(index, value, current, size); return result; } /* 复合搜索 TODO:还未调试成功*/ @RequestMapping("/multiSearch") @ResponseBody public String multiSearch(String index, FileBeanQuery query, int current, int size) throws IOException, IllegalAccessException { String result = elasticsearchService.multiSearch(index, query, current, size); return result; } /* 高亮搜索(注意QueryBuilders的查询方法) */ @RequestMapping("/highlightSearch") @ResponseBody public String highlightSearch(String index, String value, int current, int size) throws IOException { String result = elasticsearchService.highlightSearch(index, value, current, size); return result; } /* 词语补全(只能根据前缀补全) */ @RequestMapping("/suggestSearch") @ResponseBody public String suggestSearch(String index, String value) throws IOException { String result = elasticsearchService.suggestSearch(index, value); return result; } /* 全局搜索 */ @RequestMapping("/searchAll") @ResponseBody public String searchAll(String index, int current, int size) throws IOException { String result = elasticsearchService.searchAll(index, current, size); return result; }/* 查询文档总数 */ @RequestMapping("/countQuery") @ResponseBody public String countQuery(String index) throws IOException { String result = elasticsearchService.countQuery(index); return result; } }
3.service业务逻辑层
package com.demo.elasticsearch.service; import com.demo.elasticsearch.bean.FileBean; import com.demo.elasticsearch.bean.FileBeanQuery; import com.demo.elasticsearch.bean.FileMapping; import java.io.IOException; /** * @Author: ln * @Date: 2019/2/26 08:59 * @Description: */ public interface ElasticsearchService { /** * @Description: 新建索引 * @Author: ln 2019/3/1 16:51 * @Param: [index:索引名称] **/ String createIndex(String index, FileMapping mapping) throws IOException; String delIndex(String index) throws IOException; String putDocument(String index, FileBean fileBean) throws IOException; String delDocument(String index, String id) throws IOException; String getDocument(String index, String id) throws IOException; String keywordSearch(String index, String value, int current, int size) throws IOException; String multiSearch(String index, FileBeanQuery query, int current, int size) throws IOException, IllegalAccessException; String highlightSearch(String index, String value, int current, int size) throws IOException; String suggestSearch(String index, String value) throws IOException; String searchAll(String index, int current, int size) throws IOException;
String countQuery(String index) throws IOException; }
package com.demo.elasticsearch.service; import com.alibaba.fastjson.JSON; import com.demo.elasticsearch.bean.FileBean; import com.demo.elasticsearch.bean.FileBeanQuery; import com.demo.elasticsearch.bean.FileMapping; import com.demo.elasticsearch.util.AttachmentReader; import org.apache.http.HttpHost; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest; import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.delete.DeleteResponse; import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.search.MultiSearchRequest; import org.elasticsearch.action.search.MultiSearchResponse; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.client.core.CountRequest; import org.elasticsearch.client.core.CountResponse; import org.elasticsearch.common.text.Text; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightField; import org.elasticsearch.search.suggest.Suggest; import org.elasticsearch.search.suggest.SuggestBuilder; import org.elasticsearch.search.suggest.SuggestBuilders; import org.elasticsearch.search.suggest.SuggestionBuilder; import org.elasticsearch.search.suggest.completion.CompletionSuggestion; import org.springframework.stereotype.Service; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * @Author: ln * @Date: 2019/2/22 15:37 * @Description: */ @Service public class ElasticsearchServiceImpl implements ElasticsearchService { RestHighLevelClient client; @Override public String createIndex(String index, FileMapping mapping) throws IOException { client = new RestHighLevelClient( RestClient.builder(new HttpHost("localhost", 9200, "http"))); CreateIndexRequest request = new CreateIndexRequest(index); //索引配置 request.mapping("doc", "keywordName", "type=keyword", "keywordAuthor", "type=keyword", "suggestName", "type=completion", "suggestAuthor", "type=completion"); CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT); client.close(); return JSON.toJSONString(createIndexResponse); } @Override public String delIndex(String index) throws IOException { client = new RestHighLevelClient( RestClient.builder(new HttpHost("localhost", 9200, "http"))); DeleteIndexRequest request = new DeleteIndexRequest(index); AcknowledgedResponse deleteIndexResponse = client.indices().delete(request, RequestOptions.DEFAULT); System.out.println(JSON.toJSONString(deleteIndexResponse)); client.close(); return JSON.toJSONString(deleteIndexResponse.isAcknowledged()); } @Override public String putDocument(String index, FileBean fileBean) throws IOException { client = new RestHighLevelClient( RestClient.builder(new HttpHost("localhost", 9200, "http"))); File file = new File(fileBean.getFilePath()); String content = AttachmentReader.reader(fileBean.getFilePath()); fileBean.setContent(content); fileBean.setName(file.getName()); IndexRequest indexRequest = new IndexRequest(index, "doc", fileBean.getId()); indexRequest.source(JSON.toJSONString(fileBean), XContentType.JSON); IndexResponse response = client.index(indexRequest, RequestOptions.DEFAULT); System.out.println(JSON.toJSONString(response)); client.close(); return JSON.toJSONString(response.status()); } @Override public String delDocument(String index, String id) throws IOException { client = new RestHighLevelClient( RestClient.builder(new HttpHost("localhost", 9200, "http"))); DeleteRequest request = new DeleteRequest(index,"doc", id ); DeleteResponse deleteResponse = client.delete(request, RequestOptions.DEFAULT); System.out.println(JSON.toJSONString(deleteResponse)); client.close(); return JSON.toJSONString(deleteResponse.status()); } @Override public String getDocument(String index, String id) throws IOException { client = new RestHighLevelClient( RestClient.builder(new HttpHost("localhost", 9200, "http"))); GetRequest getRequest = new GetRequest(index,"doc", id ); GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT); System.out.println(JSON.toJSONString(getResponse)); client.close(); return JSON.toJSONString(getResponse); } @Override public String keywordSearch(String index, String value, int current, int size) throws IOException { client = new RestHighLevelClient( RestClient.builder(new HttpHost("localhost", 9200, "http"))); SearchRequest searchRequest = new SearchRequest(); searchRequest.indices(index); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); //支持全词搜索的字段有:keywordName,keywordAuthor" searchSourceBuilder.query(QueryBuilders.multiMatchQuery(value, "keywordName", "keywordAuthor")); searchSourceBuilder.from(current); searchSourceBuilder.size(size); searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); System.out.println(JSON.toJSONString(searchResponse)); //处理返回结果 List
4.pom.xml文件
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.3.RELEASE com.demo elasticsearch 0.0.1-SNAPSHOT elasticsearch Demo project for Spring Boot 1.8 3.16 2.4 6.2.3 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test com.alibaba fastjson 1.2.31 org.apache.pdfbox pdfbox 2.0.9 org.elasticsearch.client elasticsearch-rest-high-level-client 6.6.1 org.elasticsearch elasticsearch 6.6.1 commons-io commons-io ${commonsio.version} org.icepdf.os icepdf-pro-intl ${icepdf} net.sourceforge.jchardet jchardet 1.0 commons-beanutils commons-beanutils 1.9.2 org.apache.poi poi ${poi.version} org.apache.poi poi-ooxml ${poi.version} org.apache.poi poi-scratchpad ${poi.version} org.apache.poi poi-ooxml-schemas ${poi.version} org.springframework.boot spring-boot-maven-plugin
5.其他工具类
package com.demo.elasticsearch.util; import org.apache.commons.io.FileUtils; import org.apache.pdfbox.io.RandomAccessBuffer; import org.apache.pdfbox.pdfparser.PDFParser; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.text.PDFTextStripper; import org.apache.poi.extractor.ExtractorFactory; import java.io.File; import java.io.FileInputStream; import java.io.IOException; /** * 文档读取工具,支持word,pdf,txt * 2017年9月15日 */ public class AttachmentReader { private static final String[] WORD= {"doc","docx","xls","xlsx","ppt","pptx"}; private static final String PDF ="pdf"; private static final String TXT="txt"; public static String reader(String path) { String text = ""; String type = path.substring(path.lastIndexOf(".")+1).toLowerCase(); try { if(TXT.equals(type)) { text= txtReader(path); } else if(PDF.equals(type)) { text = pdfReader(path); } else { for (int i = 0; i < WORD.length; i++) { if(WORD[i].equals(type)){ text = wordReader(path); } } } } catch (Exception e) { e.getMessage(); } return text; }
public static String wordReader(String path) { try { return ExtractorFactory.createExtractor(new File(path)).getText(); } catch (Exception e) { System.out.println(path); throw new RuntimeException(e); } } public static String txtReader(String path) { try { File file = new File(path); //文本编码探测 FileCharsetDetector detector = new FileCharsetDetector(); String charset = detector.guessFileEncoding(file, 2); String str = FileUtils.readFileToString(file,charset); return str; } catch (Exception e) { throw new RuntimeException(e); } }
public static String pdfReader(String path) { String text = ""; FileInputStream is = null; PDDocument document = null; try { is = new FileInputStream(path); PDFParser parser = new PDFParser(new RandomAccessBuffer(is)); parser.parse(); document = parser.getPDDocument(); PDFTextStripper stripper = new PDFTextStripper(); text = stripper.getText(document); } catch (Exception e) { throw new RuntimeException(e); }finally { if(null!=is){ } try { is.close(); } catch (IOException e) { } } return text; } }
package com.demo.elasticsearch.util; import org.mozilla.intl.chardet.nsDetector; import org.mozilla.intl.chardet.nsICharsetDetectionObserver; import java.io.*; /** * 字符集探测 * 2017年9月22日 */ public class FileCharsetDetector { private boolean found = false; private String encoding = null; public String guessFileEncoding(File file) throws FileNotFoundException, IOException { return guessFileEncoding(file, new nsDetector()); }
public String guessFileEncoding(File file, int languageHint) throws FileNotFoundException, IOException { return guessFileEncoding(file, new nsDetector(languageHint)); }
private String guessFileEncoding(File file, nsDetector det) throws FileNotFoundException, IOException { // Set an observer... // The Notify() will be called when a matching charset is found. det.Init(new nsICharsetDetectionObserver() { public void Notify(String charset) { encoding = charset; found = true; } }); BufferedInputStream imp = new BufferedInputStream(new FileInputStream(file)); byte[] buf = new byte[1024]; int len; boolean done = false; boolean isAscii = false; while ((len = imp.read(buf, 0, buf.length)) != -1) { // Check if the stream is only ascii. isAscii = det.isAscii(buf, len); if (isAscii) { break; } // DoIt if non-ascii and not done yet. done = det.DoIt(buf, len, false); if (done) { break; } } imp.close(); det.DataEnd(); if (isAscii) { encoding = "ASCII"; found = true; } if (!found) { String[] prob = det.getProbableCharsets(); //这里将可能的字符集组合起来返回 for (int i = 0; i < prob.length; i++) { if (i == 0) { encoding = prob[i]; } else { encoding += "," + prob[i]; } } if (prob.length > 0) { // 在没有发现情况下,也可以只取第一个可能的编码,这里返回的是一个可能的序列 return encoding; } else { return null; } } return encoding; } }
6.springboot启动类
package com.demo.elasticsearch; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ElasticsearchApplication { public static void main(String[] args) { SpringApplication.run(ElasticsearchApplication.class, args); } }
待完善。。。