SpringBoot集成ElasticSearch(配置类版本)
项目结构图
配置文件
-
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>xc-framework-parent</artifactId> <groupId>com.xuecheng</groupId> <version>1.0-SNAPSHOT</version> <relativePath>../xc-framework-parent/pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>xc-service-search</artifactId> <dependencies> <dependency> <groupId>com.xuecheng</groupId> <artifactId>xc-framework-model</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>com.xuecheng</groupId> <artifactId>xc-framework-common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>com.xuecheng</groupId> <artifactId>xc-service-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>6.8.9</version> </dependency> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>6.8.9</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-io</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency> </dependencies> </project>
-
application.yml
server: port: ${port:40100} spring: application: name: xc-search-service xuecheng: elasticsearch: hostlist: ${eshostlist:127.0.0.1:9200} #多个结点中间用逗号分隔
-
logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration> <!--定义日志文件的存储地址,使用绝对路径--> <property name="LOG_HOME" value="/Users/xiaoge/Downloads/CMSPROJECT/logs"/> <!-- Console 输出设置 --> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> <charset>utf8</charset> </encoder> </appender> <!-- 按照每天生成日志文件 --> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!--日志文件输出的文件名--> <fileNamePattern>${LOG_HOME}/xc.%d{yyyy-MM-dd}.log</fileNamePattern> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <!-- 异步输出 --> <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"> <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --> <discardingThreshold>0</discardingThreshold> <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --> <queueSize>512</queueSize> <!-- 添加附加的appender,最多只能添加一个 --> <appender-ref ref="FILE"/> </appender> <logger name="org.apache.ibatis.cache.decorators.LoggingCache" level="DEBUG" additivity="false"> <appender-ref ref="CONSOLE"/> </logger> <logger name="org.springframework.boot" level="DEBUG"/> <root level="info"> <!--<appender-ref ref="ASYNC"/>--> <appender-ref ref="FILE"/> <appender-ref ref="CONSOLE"/> </root> </configuration>
配置类
-
ElasticsearchConfig
package com.xuecheng.search.config; import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author Administrator * @version 1.0 **/ @Configuration public class ElasticsearchConfig { @Value("${xuecheng.elasticsearch.hostlist}") private String hostlist; @Bean public RestHighLevelClient restHighLevelClient(){ //解析hostlist配置信息 String[] split = hostlist.split(","); //创建HttpHost数组,其中存放es主机和端口的配置信息 HttpHost[] httpHostArray = new HttpHost[split.length]; for(int i=0;i<split.length;i++){ String item = split[i]; httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":")[1]), "http"); } //创建RestHighLevelClient客户端 return new RestHighLevelClient(RestClient.builder(httpHostArray)); } //项目主要使用RestHighLevelClient,对于低级的客户端暂时不用 @Bean public RestClient restClient(){ //解析hostlist配置信息 String[] split = hostlist.split(","); //创建HttpHost数组,其中存放es主机和端口的配置信息 HttpHost[] httpHostArray = new HttpHost[split.length]; for(int i=0;i<split.length;i++){ String item = split[i]; httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":")[1]), "http"); } return RestClient.builder(httpHostArray).build(); } }
启动类
-
SearchApplication
package com.xuecheng.search; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.context.annotation.ComponentScan; /** * @author Administrator * @version 1.0 **/ @SpringBootApplication @EntityScan("com.xuecheng.framework.domain.search")//扫描实体类 @ComponentScan(basePackages={"com.xuecheng.api"})//扫描接口 @ComponentScan(basePackages={"com.xuecheng.search"})//扫描本项目下的所有类 @ComponentScan(basePackages={"com.xuecheng.framework"})//扫描common下的所有类 public class SearchApplication { public static void main(String[] args) throws Exception { SpringApplication.run(SearchApplication.class, args); } }
测试模块
-
TestElasticSearch
package com.xuecheng.search; import org.elasticsearch.action.DocWriteResponse; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; 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.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.action.update.UpdateResponse; import org.elasticsearch.client.IndicesClient; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.client.indices.CreateIndexResponse; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.text.Text; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.query.*; import org.elasticsearch.rest.RestStatus; 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.sort.SortOrder; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * @Author: 潇哥 * @DateTime: 2020/12/3 下午6:08 * @Description: 测试ElasticSearch */ @SpringBootTest @RunWith(SpringRunner.class) public class TestElasticSearch { @Autowired private RestHighLevelClient restHighLevelClient; @Autowired private RestClient restClient; @Test public void testCreateIndex() throws IOException { // 创建索引请求对象 CreateIndexRequest createIndexRequest = new CreateIndexRequest("xc_course"); // 设置分片, 副本 createIndexRequest.settings(Settings.builder().put("number_of_shards","1").put("number_of_replicas","0")); // 创建映射 createIndexRequest.mapping("doc","{\"properties\": {\"name\": {\"type\": \"keyword\"},\"description\": {\"type\": \"text\",\"analyzer\":\"ik_max_word\",\"search_analyzer\":\"ik_smart\"}, \"pic\":{\"type\":\"text\",\"index\":false},\"studymodel\":{\"type\":\"keyword\"} }}",XContentType.JSON); // 操作索引的客户端 IndicesClient indicesClient = restHighLevelClient.indices(); // 创建索引及映射关系 CreateIndexResponse createIndexResponse = indicesClient.create(createIndexRequest); // 得到响应结果 boolean acknowledged = createIndexResponse.isAcknowledged(); System.out.println(acknowledged); } /** * 删除索引 * @throws IOException */ @Test public void testDeleteIndex() throws IOException { // 删除索引请求对象 DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("xc_course"); // 操作索引的客户端 IndicesClient indicesClient = restHighLevelClient.indices(); // 删除索引 AcknowledgedResponse acknowledgedResponse = indicesClient.delete(deleteIndexRequest); // 得到响应 boolean acknowledged = acknowledgedResponse.isAcknowledged(); System.out.println(acknowledged); } /** * 添加文档 */ @Test public void testAddDoc() throws IOException { //准备json数据 Map<String, Object> jsonMap = new HashMap<>(); jsonMap.put("name", "spring cloud实战"); jsonMap.put("description", "本课程主要从四个章节进行讲解: 1.微服务架构入门 2.spring cloud 基础入门 3.实战Spring Boot 4.注册中心eureka。"); jsonMap.put("studymodel", "201001"); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy‐MM‐dd HH:mm:ss"); jsonMap.put("timestamp", dateFormat.format(new Date())); jsonMap.put("price", 5.6f); //索引请求对象 IndexRequest indexRequest = new IndexRequest("xc_course", "doc"); //指定索引文档内容 // 添加数据 indexRequest.source(jsonMap); //索引响应对象 IndexResponse indexResponse = restHighLevelClient.index(indexRequest); //获取响应结果 DocWriteResponse.Result result = indexResponse.getResult(); System.out.println(result); } /** * 查询文档 * @throws IOException */ @Test public void getDoc() throws IOException { // 创建get请求 GetRequest getRequest = new GetRequest( "xc_course", "doc", "AX5LKHYBrcb0-WfhRHh1"); // 查询数据 GetResponse getResponse = restHighLevelClient.get(getRequest); // 查看是否查询成功 boolean exists = getResponse.isExists(); // 获取查询数据 Map<String, Object> sourceAsMap = getResponse.getSourceAsMap(); System.out.println(sourceAsMap); } /** * 更新文档 */ @Test public void updateDoc() throws IOException { // 创建更新 UpdateRequest updateRequest = new UpdateRequest("xc_course", "doc", "AX5LKHYBrcb0-WfhRHh1"); // 输入你要更新的字段数据 Map<String, String> map = new HashMap<>(); map.put("name", "spring cloud无敌"); // 添加进类型 updateRequest.doc(map); // 执行更新 UpdateResponse update = restHighLevelClient.update(updateRequest); // 查看更新状态 RestStatus status = update.status(); System.out.println(status); } /** * 根据id删除文档 * @throws IOException */ @Test public void testDelDoc() throws IOException { //删除文档id String id = "__mapping"; //删除索引请求对象 DeleteRequest deleteRequest = new DeleteRequest("xc_course","doc",id); //响应对象 DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest); //获取响应结果 DocWriteResponse.Result result = deleteResponse.getResult(); System.out.println(result); } /** * 搜索type下的所有记录 */ @Test public void testSearchAll() throws IOException { // 搜索请求对象 SearchRequest searchRequest = new SearchRequest("xc_course"); // 设置类型 searchRequest.types("doc"); // 搜索源构建对象 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); // 搜索全部 searchSourceBuilder.query(QueryBuilders.matchAllQuery()); // source源字段过滤 searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"}, new String[]{}); // 设置搜索源 searchRequest.source(searchSourceBuilder); // 执行搜索 SearchResponse searchResponse = restHighLevelClient.search(searchRequest); // 搜索匹配结果 SearchHits hits = searchResponse.getHits(); // 搜索总记录数 long totalHits = hits.totalHits; // 匹配度较高的前N个文档 SearchHit[] searchHits = hits.getHits(); for (SearchHit hit : searchHits) { String index = hit.getIndex(); String type = hit.getType(); String id = hit.getId(); float score = hit.getScore(); String sourceAsString = hit.getSourceAsString(); Map<String, Object> sourceAsMap = hit.getSourceAsMap(); String name = (String) sourceAsMap.get("name"); String studymodel = (String) sourceAsMap.get("studymodel"); // 因为上面过滤了该字段, 所有该字段的数据是取不到的 String description = (String) sourceAsMap.get("description"); System.out.println(name); System.out.println(studymodel); System.out.println(description); } } /** * 搜索type下的当前页记录 */ @Test public void testSearchPage() throws IOException { // 搜索请求对象 SearchRequest searchRequest = new SearchRequest("xc_course"); // 设置类型 searchRequest.types("doc"); // 搜索源构建对象 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); // 搜索全部 searchSourceBuilder.query(QueryBuilders.matchAllQuery()); int page = 1; int size = 1; // 获取从那条记录开始 int from = (page - 1) * size; // 从当前记录开始 searchSourceBuilder.from(from); // 每页展示的记录数 searchSourceBuilder.size(size); // source源字段过滤 searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"}, new String[]{}); // 设置搜索源 searchRequest.source(searchSourceBuilder); // 执行搜索 SearchResponse searchResponse = restHighLevelClient.search(searchRequest); // 搜索匹配结果 SearchHits hits = searchResponse.getHits(); // 搜索总记录数 long totalHits = hits.totalHits; // 匹配度较高的前N个文档 SearchHit[] searchHits = hits.getHits(); for (SearchHit hit : searchHits) { String index = hit.getIndex(); String type = hit.getType(); String id = hit.getId(); float score = hit.getScore(); String sourceAsString = hit.getSourceAsString(); Map<String, Object> sourceAsMap = hit.getSourceAsMap(); String name = (String) sourceAsMap.get("name"); String studymodel = (String) sourceAsMap.get("studymodel"); // 因为上面过滤了该字段, 所有该字段的数据是取不到的 String description = (String) sourceAsMap.get("description"); System.out.println(name); System.out.println(studymodel); System.out.println(description); } } /** * TermQuery: 精确查询,在搜索时会整体匹配关键字,不再将关键字分词 */ @Test public void testTermQuery() throws IOException { // 搜索请求对象 SearchRequest searchRequest = new SearchRequest("xc_course"); // 设置类型 searchRequest.types("doc"); // 搜索源构建对象 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); // 搜索精准查询, 不分词 searchSourceBuilder.query(QueryBuilders.termQuery("name","spring")); // source源字段过滤 searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"}, new String[]{}); // 设置搜索源 searchRequest.source(searchSourceBuilder); // 执行搜索 SearchResponse searchResponse = restHighLevelClient.search(searchRequest); // 搜索匹配结果 SearchHits hits = searchResponse.getHits(); // 搜索总记录数 long totalHits = hits.totalHits; // 匹配度较高的前N个文档 SearchHit[] searchHits = hits.getHits(); for (SearchHit hit : searchHits) { String index = hit.getIndex(); String type = hit.getType(); String id = hit.getId(); float score = hit.getScore(); String sourceAsString = hit.getSourceAsString(); Map<String, Object> sourceAsMap = hit.getSourceAsMap(); String name = (String) sourceAsMap.get("name"); String studymodel = (String) sourceAsMap.get("studymodel"); // 因为上面过滤了该字段, 所有该字段的数据是取不到的 String description = (String) sourceAsMap.get("description"); System.out.println(name); System.out.println(studymodel); System.out.println(description); } } /** * TermsQuery: 根据id精确匹配 */ @Test public void testTermsQuery() throws IOException { // 搜索请求对象 SearchRequest searchRequest = new SearchRequest("xc_course"); // 设置类型 searchRequest.types("doc"); // 搜索源构建对象 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); String[] values = new String[] {"1", "2"}; // 搜索精准查询, 不分词 searchSourceBuilder.query(QueryBuilders.termsQuery("_id",values)); // source源字段过滤 searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"}, new String[]{}); // 设置搜索源 searchRequest.source(searchSourceBuilder); // 执行搜索 SearchResponse searchResponse = restHighLevelClient.search(searchRequest); // 搜索匹配结果 SearchHits hits = searchResponse.getHits(); // 搜索总记录数 long totalHits = hits.totalHits; // 匹配度较高的前N个文档 SearchHit[] searchHits = hits.getHits(); for (SearchHit hit : searchHits) { String index = hit.getIndex(); String type = hit.getType(); String id = hit.getId(); float score = hit.getScore(); String sourceAsString = hit.getSourceAsString(); Map<String, Object> sourceAsMap = hit.getSourceAsMap(); String name = (String) sourceAsMap.get("name"); String studymodel = (String) sourceAsMap.get("studymodel"); // 因为上面过滤了该字段, 所有该字段的数据是取不到的 String description = (String) sourceAsMap.get("description"); System.out.println(name); System.out.println(studymodel); System.out.println(description); } } /** * MatchQuery: 即全文检索,它的搜索方式是先将搜索字符串分词,再使用各各词条从索引中搜索 * * query:搜索的关键字,对于英文关键字如果有多个单词则中间要用半角逗号分隔,而对于中文关键字中间可以用 逗号分隔也可以不用。 * * operator:or 表示 只要有一个词在文档中出现则就符合条件,and表示每个词都在文档中出现则才符合条件 */ @Test public void testMatchQuery() throws IOException { // 搜索请求对象 SearchRequest searchRequest = new SearchRequest("xc_course"); // 设置类型 searchRequest.types("doc"); // 搜索源构建对象 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); // 搜索字符串分词, operator为or(或) searchSourceBuilder.query(QueryBuilders.matchQuery("description", "spring java").operator(Operator.AND)); // source源字段过滤 searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"}, new String[]{}); // 设置搜索源 searchRequest.source(searchSourceBuilder); // 执行搜索 SearchResponse searchResponse = restHighLevelClient.search(searchRequest); // 搜索匹配结果 SearchHits hits = searchResponse.getHits(); // 搜索总记录数 long totalHits = hits.totalHits; // 匹配度较高的前N个文档 SearchHit[] searchHits = hits.getHits(); for (SearchHit hit : searchHits) { String index = hit.getIndex(); String type = hit.getType(); String id = hit.getId(); float score = hit.getScore(); String sourceAsString = hit.getSourceAsString(); Map<String, Object> sourceAsMap = hit.getSourceAsMap(); String name = (String) sourceAsMap.get("name"); String studymodel = (String) sourceAsMap.get("studymodel"); // 因为上面过滤了该字段, 所有该字段的数据是取不到的 String description = (String) sourceAsMap.get("description"); System.out.println(name); System.out.println(studymodel); System.out.println(description); } } /** * MatchQuery: 即全文检索,它的搜索方式是先将搜索字符串分词,再使用各各词条从索引中搜索 * * query:搜索的关键字,对于英文关键字如果有多个单词则中间要用半角逗号分隔,而对于中文关键字中间可以用 逗号分隔也可以不用。 * * 设置"minimum_should_match": "80%"表示,三个词在文档的匹配占比为80%,即3*0.8=2.4,向上取整得2,表 * 示至少有两个词在文档中要匹配成功 */ @Test public void testMatchQueryMinimumShouldMatch() throws IOException { // 搜索请求对象 SearchRequest searchRequest = new SearchRequest("xc_course"); // 设置类型 searchRequest.types("doc"); // 搜索源构建对象 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); // 搜索字符串分词, 百分比查询 searchSourceBuilder.query(QueryBuilders.matchQuery("description", "spring开发框架").minimumShouldMatch("80%")); // source源字段过滤 searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"}, new String[]{}); // 设置搜索源 searchRequest.source(searchSourceBuilder); // 执行搜索 SearchResponse searchResponse = restHighLevelClient.search(searchRequest); // 搜索匹配结果 SearchHits hits = searchResponse.getHits(); // 搜索总记录数 long totalHits = hits.totalHits; // 匹配度较高的前N个文档 SearchHit[] searchHits = hits.getHits(); for (SearchHit hit : searchHits) { String index = hit.getIndex(); String type = hit.getType(); String id = hit.getId(); float score = hit.getScore(); String sourceAsString = hit.getSourceAsString(); Map<String, Object> sourceAsMap = hit.getSourceAsMap(); String name = (String) sourceAsMap.get("name"); String studymodel = (String) sourceAsMap.get("studymodel"); // 因为上面过滤了该字段, 所有该字段的数据是取不到的 String description = (String) sourceAsMap.get("description"); System.out.println(name); System.out.println(studymodel); System.out.println(description); } } /** * multiQuery,一次可以匹配多个字段 * minimumShouldMatch: 匹配的百分比 * field: 设置字段, 扩大权重 * 字段: 指定要设置权重的字段 * boost: 匹配多个字段时可以提升字段的boost(权重)来提高得分 * @throws IOException */ @Test public void testMultiMatchQuery() throws IOException { // 搜索请求对象 SearchRequest searchRequest = new SearchRequest("xc_course"); // 设置类型 searchRequest.types("doc"); // 搜索源构建对象 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); // 一次可以匹配多个字段, name, description searchSourceBuilder.query(QueryBuilders.multiMatchQuery("spring css", "name","description").minimumShouldMatch("50%").field("name",10)); // source源字段过滤 searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"}, new String[]{}); // 设置搜索源 searchRequest.source(searchSourceBuilder); // 执行搜索 SearchResponse searchResponse = restHighLevelClient.search(searchRequest); // 搜索匹配结果 SearchHits hits = searchResponse.getHits(); // 搜索总记录数 long totalHits = hits.totalHits; // 匹配度较高的前N个文档 SearchHit[] searchHits = hits.getHits(); for (SearchHit hit : searchHits) { String index = hit.getIndex(); String type = hit.getType(); String id = hit.getId(); float score = hit.getScore(); String sourceAsString = hit.getSourceAsString(); Map<String, Object> sourceAsMap = hit.getSourceAsMap(); String name = (String) sourceAsMap.get("name"); String studymodel = (String) sourceAsMap.get("studymodel"); // 因为上面过滤了该字段, 所有该字段的数据是取不到的 String description = (String) sourceAsMap.get("description"); System.out.println(name); System.out.println(studymodel); System.out.println(description); } } /** * 布尔查询对应于Lucene的BooleanQuery查询,实现将多个查询组合起来 * * must:文档必须匹配must所包括的查询条件,相当于 “AND” * should:文档应该匹配should所包括的查询条件其 中的一个或多个,相当于 "OR" * must_not:文档不能匹配must_not所包括的该查询条件,相当于“NOT” * * * @throws IOException */ @Test public void testBooleanQuery() throws IOException { // 搜索请求对象 SearchRequest searchRequest = new SearchRequest("xc_course"); // 设置类型 searchRequest.types("doc"); // 搜索源构建对象 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); // 定义MultiMatchQueryBuilder MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("spring css", "name", "description").minimumShouldMatch("50%").field("name", 10); // 在定义termQueryBuilder TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("studymodel", "201001"); // 在定义boolQueryBuilder BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder(); // 把之前定义的查询条件, 添加到boolQueryBuilder的must里 boolQueryBuilder.must(multiMatchQueryBuilder); boolQueryBuilder.must(termQueryBuilder); // 添加boolQueryBuilder的查询条件 searchSourceBuilder.query(boolQueryBuilder); // source源字段过滤 searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"}, new String[]{}); // 设置搜索源 searchRequest.source(searchSourceBuilder); // 执行搜索 SearchResponse searchResponse = restHighLevelClient.search(searchRequest); // 搜索匹配结果 SearchHits hits = searchResponse.getHits(); // 搜索总记录数 long totalHits = hits.totalHits; // 匹配度较高的前N个文档 SearchHit[] searchHits = hits.getHits(); for (SearchHit hit : searchHits) { String index = hit.getIndex(); String type = hit.getType(); String id = hit.getId(); float score = hit.getScore(); String sourceAsString = hit.getSourceAsString(); Map<String, Object> sourceAsMap = hit.getSourceAsMap(); String name = (String) sourceAsMap.get("name"); String studymodel = (String) sourceAsMap.get("studymodel"); // 因为上面过滤了该字段, 所有该字段的数据是取不到的 String description = (String) sourceAsMap.get("description"); System.out.println(name); System.out.println(studymodel); System.out.println(description); } } /** * Filter: 过虑是针对搜索的结果进行过虑,过虑器主要判断的是文档是否匹配,不去计算和判断文档的匹配度得分,所以过 * 虑器性能比查询要高,且方便缓存,推荐尽量使用过虑器去实现查询或者过虑器和查询共同使用 * * range: 范围过虑,保留大于等于60 并且小于等于100的记录。 * * term: 项匹配过滤, 保留studymodel等于"201001"的记录 * * @throws IOException */ @Test public void testFilter() throws IOException { // 搜索请求对象 SearchRequest searchRequest = new SearchRequest("xc_course"); // 设置类型 searchRequest.types("doc"); // 搜索源构建对象 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); // 定义MultiMatchQueryBuilder MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("spring css", "name", "description").minimumShouldMatch("50%").field("name", 10); // 在定义boolQueryBuilder BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder(); // 把之前定义的查询条件, 添加到boolQueryBuilder的must里 boolQueryBuilder.must(multiMatchQueryBuilder); // 定义过滤器 // 过滤出studymodel字段为201001的记录 boolQueryBuilder.filter(QueryBuilders.termQuery("studymodel", "201001")); // 过滤出, price字段值, 大于80小于100的记录 boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(80).lte(100)); // 添加boolQueryBuilder的查询条件 searchSourceBuilder.query(boolQueryBuilder); // source源字段过滤 searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"}, new String[]{}); // 设置搜索源 searchRequest.source(searchSourceBuilder); // 执行搜索 SearchResponse searchResponse = restHighLevelClient.search(searchRequest); // 搜索匹配结果 SearchHits hits = searchResponse.getHits(); // 搜索总记录数 long totalHits = hits.totalHits; // 匹配度较高的前N个文档 SearchHit[] searchHits = hits.getHits(); for (SearchHit hit : searchHits) { String index = hit.getIndex(); String type = hit.getType(); String id = hit.getId(); float score = hit.getScore(); String sourceAsString = hit.getSourceAsString(); Map<String, Object> sourceAsMap = hit.getSourceAsMap(); String name = (String) sourceAsMap.get("name"); String studymodel = (String) sourceAsMap.get("studymodel"); // 因为上面过滤了该字段, 所有该字段的数据是取不到的 String description = (String) sourceAsMap.get("description"); System.out.println(name); System.out.println(studymodel); System.out.println(description); } } /** * Sort: 可以在字段上添加一个或多个排序,支持在keyword、date、float等类型上添加,text类型的字段上不允许添加排序 * @throws IOException */ @Test public void testSort() throws IOException { // 搜索请求对象 SearchRequest searchRequest = new SearchRequest("xc_course"); // 设置类型 searchRequest.types("doc"); // 搜索源构建对象 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); // 在定义boolQueryBuilder BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder(); // 过滤出, price字段值, 大于80小于100的记录 boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(80).lte(100)); // 添加boolQueryBuilder的查询条件 searchSourceBuilder.query(boolQueryBuilder); // 定义排序字段 searchSourceBuilder.sort("studymodel", SortOrder.DESC); searchSourceBuilder.sort("price", SortOrder.ASC); // source源字段过滤 searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"}, new String[]{}); // 设置搜索源 searchRequest.source(searchSourceBuilder); // 执行搜索 SearchResponse searchResponse = restHighLevelClient.search(searchRequest); // 搜索匹配结果 SearchHits hits = searchResponse.getHits(); // 搜索总记录数 long totalHits = hits.totalHits; // 匹配度较高的前N个文档 SearchHit[] searchHits = hits.getHits(); for (SearchHit hit : searchHits) { String index = hit.getIndex(); String type = hit.getType(); String id = hit.getId(); float score = hit.getScore(); String sourceAsString = hit.getSourceAsString(); Map<String, Object> sourceAsMap = hit.getSourceAsMap(); String name = (String) sourceAsMap.get("name"); String studymodel = (String) sourceAsMap.get("studymodel"); // 因为上面过滤了该字段, 所有该字段的数据是取不到的 String description = (String) sourceAsMap.get("description"); System.out.println(name); System.out.println(studymodel); System.out.println(description); } } /** * Highlight: 高亮显示可以将搜索结果一个或多个字突出显示,以便向用户展示匹配关键字的位置 * @throws IOException */ @Test public void testHighlight() throws IOException { // 搜索请求对象 SearchRequest searchRequest = new SearchRequest("xc_course"); // 设置类型 searchRequest.types("doc"); // 搜索源构建对象 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); // source源字段过滤 searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"}, new String[]{}); // 定义MultiMatchQueryBuilder MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("开发框架", "name", "description").minimumShouldMatch("50%").field("name", 10); // 在定义boolQueryBuilder BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder(); // 添加搜索条件到 must中 boolQueryBuilder.must(multiMatchQueryBuilder); // 过滤出, price字段值, 大于80小于100的记录 boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(0).lte(100)); // 添加boolQueryBuilder的查询条件 searchSourceBuilder.query(boolQueryBuilder); // 定义排序字段 searchSourceBuilder.sort("price", SortOrder.ASC); // 高亮设置 HighlightBuilder highlightBuilder = new HighlightBuilder(); // 设置前缀 highlightBuilder.preTags("<tag>"); // 设置后缀 highlightBuilder.postTags("</tag>"); // 设置高亮字段 highlightBuilder.fields().add(new HighlightBuilder.Field("name")); // 把highlightBuilder添加到条件里 searchSourceBuilder.highlighter(highlightBuilder); // 设置搜索源 searchRequest.source(searchSourceBuilder); // 执行搜索 SearchResponse searchResponse = restHighLevelClient.search(searchRequest); // 搜索匹配结果 SearchHits hits = searchResponse.getHits(); // 搜索总记录数 long totalHits = hits.totalHits; // 匹配度较高的前N个文档 SearchHit[] searchHits = hits.getHits(); for (SearchHit hit : searchHits) { Map<String, Object> sourceAsMap = hit.getSourceAsMap(); String name = (String) sourceAsMap.get("name"); // 获取高亮信息 Map<String, HighlightField> highlightFields = hit.getHighlightFields(); if (highlightFields != null) { // 取出高亮字段内容 HighlightField highlightField = highlightFields.get("name"); if (highlightField == null) { continue; } // 获取内容 Text[] texts = highlightField.getFragments(); StringBuilder stringBuilder = new StringBuilder(); for (Text text : texts) { stringBuilder.append(text.toString()); } name = stringBuilder.toString(); } String studymodel = (String) sourceAsMap.get("studymodel"); // 因为上面过滤了该字段, 所有该字段的数据是取不到的 String description = (String) sourceAsMap.get("description"); System.out.println(name); System.out.println(studymodel); System.out.println(description); } } }