赞
踩
环境准备:
Elasticsearch服务器
ik中文分词器
Kibana服务
一个集成了ES的springboot项目
博主环境:
es:6.2.2 Kibana:6.2.2 springboot:2.1.2
定义成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"
}
}
}
}
结果正确:
测试方法
@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; }
输出结果正确:
封装的工具方法
/** * 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="请搜索..">
Fuzzy有纠错功能
应用Fuzzy查询的字段需要是 text 类型的。
GET /indextest/testmapping/_search/
{
"query": {
"fuzzy": {
"namePinyin": {
"value": "zhonghuarenmingonghegu"
}
}
} ,
"highlight" :{
"fields": {
"namePinyin" :{}
}
}
}
/** * 拼音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; }
这个可以用作标签查询、定位。
elasticsearch报日志:
org.elasticsearch.ElasticsearchSecurityException: current license is
non-compliant for [security]
替换许可证
到elastic**官网**https://register.elastic.co/
注册一下账号,注册邮箱会收到许可证文件
将许可证放到服务器下,用的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
这样就ok了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。