环境准备:
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 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 getScores() {
return scores;
}
public void setScores(List scores) {
this.scores = scores;
}
@Field(type=FieldType.Auto)
private String name;
@Field(type=FieldType.Auto)
private Integer age;
@Field(type=FieldType.Auto)
private List 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{
}
在程序里插入一些数据;
@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 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 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 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 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 suggests = Arrays.asList(suggestSet.toArray(new String[]{}));
suggests.forEach((s)->{
System.out.println(s);
});
return suggests;
}
前端自动补全用JqueryUI的autocomplete组件。
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 listSearchByPinyin(String field,String value,String highlightField ,String preTag,String postTag,String index, String indexType , ElasticsearchTemplate elasticsearchTemplate){
List 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