springboot集成Elasticsearch实现各种搜索功能

首页 / 新闻资讯 / 正文

First Vector Graphic

环境准备:
Elasticsearch服务器
ik中文分词器
Kibana服务
一个集成了ES的springboot项目

博主环境:
es:6.2.2 Kibana:6.2.2 springboot:2.1.2

springboot集成Elasticsearch使用completion suggest实现自动关键字补全

定义成completion的字段无法应用highlight返回。

实现目标:建立学生数据索引,以学生姓名为搜索自动补全字段。
学生实体类:

@Document(indexName = "student_index",type="student") public class Student implements Serializable {     @Id     @Field(type= FieldType.Auto)     private String studentId;      @Override     public String toString() {         return "Student{" +                 "studentId='" + studentId + '\'' +                 ", name='" + name + '\'' +                 ", age=" + age +                 ", scores=" + scores +                 '}';     }      public Student(String studentId, String name, Integer age, List<Double> scores) {         this.studentId = studentId;         this.name = name;         this.age = age;         this.scores = scores;     }      public Student() {      }      public String getStudentId() {          return studentId;     }      public void setStudentId(String studentId) {         this.studentId = studentId;     }      public String getName() {         return name;     }      public void setName(String name) {         this.name = name;     }      public Integer getAge() {         return age;     }      public void setAge(Integer age) {         this.age = age;     }      public List<Double> getScores() {         return scores;     }      public void setScores(List<Double> scores) {         this.scores = scores;     }      @Field(type=FieldType.Auto)     private String name;      @Field(type=FieldType.Auto)     private Integer age;      @Field(type=FieldType.Auto)     private List<Double> scores; }

建立学生的索引和映射:

待搜索的字段需要设置为Completion类型

PUT /student_index {    "mappings": {      "student" : {        "properties" : {          "name" : {            "type" :    "completion",            "analyzer": "ik_smart"          },          "age" : {            "type" :   "integer"          },                  "studentId" : {            "type" :   "text"          },                  "scores":{           "type" :  "float"                    }               }      }    }  }

整点数据测试一下:

学生索引Repository类:

@Repository public interface StudentRepository extends ElasticsearchCrudRepository<Student,String>{ }

开始测试:

在程序里插入一些数据;

@Autowired 	private ElasticsearchTemplate elasticsearchTemplate; 	@Test 	public void contextLoads() {  		List scores= new ArrayList<>(); 		scores.add(67.2); 		scores.add(27.2); 		scores.add(56.2);  /*		studentIndexRepository.save(new Student(UUID.randomUUID().toString(), "张三", 21, scores )); 		studentIndexRepository.save(new Student(UUID.randomUUID().toString(), "李四", 35, scores )); 		studentIndexRepository.save(new Student(UUID.randomUUID().toString(), "王二", 45, scores )); 		studentIndexRepository.save(new Student(UUID.randomUUID().toString(), "张大林", 23, scores )); 		studentIndexRepository.save(new Student(UUID.randomUUID().toString(), "王大力", 51, scores ));*/  		studentIndexRepository.save(new Student(UUID.randomUUID().toString(), "刘伯", 21, scores )); 		studentIndexRepository.save(new Student(UUID.randomUUID().toString(), "刘思想", 35, scores )); 		studentIndexRepository.save(new Student(UUID.randomUUID().toString(), "王皮皮", 45, scores )); 		studentIndexRepository.save(new Student(UUID.randomUUID().toString(), "王二丫", 23, scores )); 		studentIndexRepository.save(new Student(UUID.randomUUID().toString(), "王铁蛋", 51, scores )); 	}

在Kibana测试

POST /student_index/completion/_search { "size": 0,   "suggest": {     "name-suggest": {       "prefix": "王二",       "completion": {         "field": "name"       }     }   } }

结果正确:
springboot集成Elasticsearch实现各种搜索功能

接下来是实现获取suggest的代码:

测试方法

	@Test 	public void testSuggestCompletionProc() {  		String suggestField="name";//指定在哪个字段搜索 		String suggestValue="王二";//输入的信息 		Integer suggestMaxCount=10;//获得最大suggest条数  		CompletionSuggestionBuilder suggestionBuilderDistrict = new CompletionSuggestionBuilder(suggestField).prefix(suggestValue).size(suggestMaxCount); 		SuggestBuilder suggestBuilder = new SuggestBuilder(); 		suggestBuilder.addSuggestion("student_suggest", suggestionBuilderDistrict);//添加suggest  		//设置查询builder的index,type,以及建议 		SearchRequestBuilder requestBuilder = this.elasticsearchTemplate.getClient().prepareSearch("student_index").setTypes("student").suggest(suggestBuilder); 		System.out.println(requestBuilder.toString());  		SearchResponse response = requestBuilder.get(); 		Suggest suggest = response.getSuggest();//suggest实体  		Set<String> suggestSet = new HashSet<>();//set 		int maxSuggest = 0; 		if (suggest != null) { 			Suggest.Suggestion result = suggest.getSuggestion("student_suggest");//获取suggest,name任意string 			for (Object term : result.getEntries()) {  				if (term instanceof CompletionSuggestion.Entry) { 					CompletionSuggestion.Entry item = (CompletionSuggestion.Entry) term; 					if (!item.getOptions().isEmpty()) { 						//若item的option不为空,循环遍历 						for (CompletionSuggestion.Entry.Option option : item.getOptions()) { 							String tip = option.getText().toString(); 							if (!suggestSet.contains(tip)) { 								suggestSet.add(tip); 								++maxSuggest; 							} 						} 					} 				} 				if (maxSuggest >= suggestMaxCount) { 					break; 				} 			} 		}  		List<String> suggests = Arrays.asList(suggestSet.toArray(new String[]{}));  		suggests.forEach((s)->{ 			System.out.println(s); 		});  //		return	 suggests;  	}

输出结果正确:
springboot集成Elasticsearch实现各种搜索功能
封装的工具方法

    /**      * completion suggest      * @param suggestField      * @param suggestValue      * @param suggestMaxCount      * @param index_      * @param indexType_      * @param elasticsearchTemplate__      * @return      */     public List<String> listSuggestCompletion(String suggestField, String suggestValue, Integer suggestMaxCount,String index_,String indexType_,ElasticsearchTemplate elasticsearchTemplate__) {         /* String suggestField="name";//指定在哪个字段搜索         String suggestValue="王二";//输入的信息         Integer suggestMaxCount=10;//获得最大suggest条数*/          CompletionSuggestionBuilder suggestionBuilderDistrict = new CompletionSuggestionBuilder(suggestField).prefix(suggestValue).size(suggestMaxCount);         SuggestBuilder suggestBuilder = new SuggestBuilder();         suggestBuilder.addSuggestion("student_suggest", suggestionBuilderDistrict);//添加suggest          //设置查询builder的index,type,以及建议         if(elasticsearchTemplate__==null)             System.out.println( "this is Template null  ***************************************************");         SearchRequestBuilder requestBuilder = elasticsearchTemplate__.getClient().prepareSearch(index_).setTypes(indexType_).suggest(suggestBuilder);         System.out.println(requestBuilder.toString());          SearchResponse response = requestBuilder.get();         Suggest suggest = response.getSuggest();//suggest实体          Set<String> suggestSet = new HashSet<>();//set         int maxSuggest = 0;         if (suggest != null) {             Suggest.Suggestion result = suggest.getSuggestion("student_suggest");//获取suggest,name任意string             for (Object term : result.getEntries()) {                  if (term instanceof CompletionSuggestion.Entry) {                     CompletionSuggestion.Entry item = (CompletionSuggestion.Entry) term;                     if (!item.getOptions().isEmpty()) {                         //若item的option不为空,循环遍历                         for (CompletionSuggestion.Entry.Option option : item.getOptions()) {                             String tip = option.getText().toString();                             if (!suggestSet.contains(tip)) {                                 suggestSet.add(tip);                                 ++maxSuggest;                             }                         }                     }                 }                 if (maxSuggest >= suggestMaxCount) {                     break;                 }             }         }          List<String> suggests = Arrays.asList(suggestSet.toArray(new String[]{}));          suggests.forEach((s)->{             System.out.println(s);         });  		return	 suggests;      }

前端代码

前端自动补全用JqueryUI的autocomplete组件。

<script>      var availableTags = new Array();      $(function() {          $("#tags").autocomplete({             source: availableTags          });     });      $(document).ready(function() {         $("#tags").bind("input propertychange", function () {             $("#valuetext").html($(this).val());             $.get("searchSuggest?value="+$(this).val(), function (data, status) {                 var results=data;                 for(var i=0;i<results.length;i++){                     availableTags[i]=results[i].texts;                 }                  $("#tags").autocomplete({                     source: availableTags                  });             });         });     }) </script>  <!-- 标签 -->             <input type="search" id="tags" name="searchvalue" class="form-control" style="border-radius: 50px 0 0 50px;" placeholder="请搜索..">

springboot集成Elasticsearch实现各种搜索功能


实现Fuzzy模糊查询

Fuzzy有纠错功能
应用Fuzzy查询的字段需要是 text 类型的。

es中的Fuzzy查询语句示例

GET /indextest/testmapping/_search/ {   "query": {     "fuzzy": {       "namePinyin": {         "value": "zhonghuarenmingonghegu"       }      }    } ,   "highlight" :{     "fields": {       "namePinyin" :{}     }   } }

springboot集成Elasticsearch实现各种搜索功能

Java实现Fuzzy和高亮返回

    /**      * 拼音Fuzzy查询      * @param field      * @param value      * @param highlightField      * @param preTag      * @param postTag      * @param index      * @param indexType      * @param elasticsearchTemplate      * @return      */     public List<String> listSearchByPinyin(String field,String value,String highlightField ,String preTag,String postTag,String index, String indexType , ElasticsearchTemplate elasticsearchTemplate){          List<String> result = new LinkedList<>();          FuzzyQueryBuilder queryBuilder = QueryBuilders.fuzzyQuery(field, value)                 .fuzziness(Fuzziness.TWO)                 .prefixLength(0)                 .maxExpansions(10);         HighlightBuilder highlightBuilder = new HighlightBuilder();         highlightBuilder.field(highlightField);         highlightBuilder.preTags(preTag);         highlightBuilder.postTags(postTag);          SearchRequestBuilder requestBuilder = elasticsearchTemplate.getClient().prepareSearch(index)                 .setTypes(indexType)                 .setQuery(queryBuilder)                 .highlighter(highlightBuilder);           SearchResponse response = requestBuilder.get();          System.out.println(response.getClusters().toString());          System.out.println(requestBuilder.toString());          SearchHits searchHits = response.getHits();          searchHits.forEach(i->{             System.out.println(i.getIndex());             System.out.println(i.getId());             System.out.println(i.getSourceAsString());               Text highlightFragment = i.getHighlightFields().get(highlightField).getFragments()[0];              result.add(highlightFragment.toString());              System.out.println();          });           return result;     }

数组元素查询

这个可以用作标签查询、定位。
springboot集成Elasticsearch实现各种搜索功能

Elasticsearch许可证过期

elasticsearch报日志:

org.elasticsearch.ElasticsearchSecurityException: current license is
non-compliant for [security]

替换许可证

到elastic**官网**https://register.elastic.co/注册一下账号,注册邮箱会收到许可证文件
springboot集成Elasticsearch实现各种搜索功能
将许可证放到服务器下,用的docker要进入到es容器内,重命名许可证文件名为:license.json

# curl -XPUT -u elastic:yourregistername 'http://133.3.269.211:9200/_xpack/license?acknowledge=true' -H "Content-Type: application/json" -d @license.json

springboot集成Elasticsearch实现各种搜索功能
这样就ok了。