Elasticsearch全文检索:根据关键词对全文查询检索,关键词也分词处理

时间:2025-04-04 08:40:45

之前看过了solr的全文检索工具,原理比较简单,理解起来也快;这次我们项目上要求用Elasticsearch实现全文检索,据说这个插件功能更厉害,但是也没有具体研究过;这里就省略了es的部署过程和集成springboot的方法了,直接附上我的后台查询代码;


import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;

import ;
import ;
import ;
import ;

@Service
public class ElasticsearchServiceImpl implements ElasticsearchService {

    @Autowired
    JestClient jestClient;

    @Override
    public List<EsFileInfo> findPublishedFileByKeyWord(String keyWord, int pageNum, int pageSize) {
        //处理特殊字符
        keyWord = (keyWord);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        (()
                                                .should(/*(keyWord).field("FILE_NAME")*/("FILE_NAME",keyWord).analyzer("ik_smart"))
                                                .should(/*(keyWord).field("")*/("",keyWord).analyzer("ik_smart")));
        //初始化高亮对象
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        ("FILE_NAME");//高亮title
        ("");
        ("<span style='color:red'>").postTags("</span>");//高亮标签
        //设置高亮
        (highlightBuilder);
        //设置起始页
        ((pageNum - 1) * pageSize);
        //设置页大小
        (pageSize);
        //指定索引
        Search search = new (())
                .addIndex("book")
                .build();
        SearchResult result = null ;
        List<EsFileInfo> list = new ArrayList<>();
        try {
            //执行查询操作
            result = (search);
            ("本次查询共查到:"+()+"个关键字!"+());
            List<<EsFileInfo,Void>> hits = ();
            for (<EsFileInfo,Void> hit : hits) {
                EsFileInfo source = ;
                //获取高亮后的内容
                Map<String, List<String>> highlight = ;
                List<String> file_name = ("FILE_NAME");//高亮后的title
                if(file_name!=null){
                    source.setFile_name(file_name.get(0));
                }
                List<String> content = ("");//高亮后的title
                if(content!=null){
                    ().setContent((0));
                }
                ("姓名:"+source.getFile_name());
                ("作者:"+().getAuthor());
                ("内容:"+().getContent());
                (source);
            }
            return list;
        } catch (IOException e) {
            ();
            return new ArrayList<>();
        }
    }

    @Override
    public int findPublishedCountByKeyWord(String keyWord) {
        //处理特殊字符
        keyWord = (keyWord);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        (()
                .should((keyWord).field("FILE_NAME"))
                .should((keyWord).field("")));
        //初始化高亮对象
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        ("FILE_NAME");//高亮title
        ("");
        ("<span style='color:red'>").postTags("</span>");//高亮标签
        //设置高亮
        (highlightBuilder);
        //设置页大小
        (10000);
        //指定索引
        Search search = new (())
                .addIndex("book")
                .build();
        SearchResult result = null ;
        try {
            result = (search);
            ("本次查询共查到:"+()+"个关键字!"+());
            List<<EsFileInfo,Void>> hits = ();
            return ();
        } catch (IOException e) {
            ();
            return new ArrayList<>().size();
        }
    }
}


import ;
import ;

import ;

/**
 * es查询出的文件信息结果类
 */
public class EsFileInfo {

    @SerializedName("FILE_ID")
    private String file_id;

    @SerializedName("FILE_NAME")
    private String file_name;

    @SerializedName("FILE_SAVE_NAME")
    private String file_save_name;
    //编译成另一个名字
    @SerializedName("attachment")
    private EsDoc esDoc;

    public String getFile_id() {
        return file_id;
    }

    public void setFile_id(String file_id) {
        this.file_id = file_id;
    }

    public String getFile_name() {
        return file_name;
    }

    public void setFile_name(String file_name) {
        this.file_name = file_name;
    }

    public String getFile_save_name() {
        return file_save_name;
    }

    public void setFile_save_name(String file_save_name) {
        this.file_save_name = file_save_name;
    }

    public EsDoc getEsDoc() {
        return esDoc;
    }

    public void setEsDoc(EsDoc esDoc) {
         = esDoc;
    }
}
package ;

import ;

/**
 * 文件实体附件类
 */
public class EsDoc {

    //    @SerializedName("")
    private String author;

    //    @SerializedName("")
    private String content;

    //    @SerializedName("")
    private String date;

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
         = author;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
         = content;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
         = date;
    }
}

QueryBuilders的几个分词方法的区别:


    /**
     * 默认的standard analyzer分词规则:<br>
     * 去掉大部分标点符号,并以此分割原词为多个词,把分分割后的词转为小写放入token组中。<br>
     * 对于not-analyzed的词,直接把原词放入token组中。<br>
     * matchQuery的机制是:先检查字段类型是否是analyzed,如果是,则先分词,再去去匹配token;如果不是,则直接去匹配token。<br>
     * id=id2,默认分词,id2不分词。<br>
     * 以wwIF5-vP3J4l3GJ6VN3h为例:<br>
     * id是的token组是[wwif5,vp3j4l3gj6vn3h]<br>
     * id2的token组是[wwIF5-vP3J4l3GJ6VN3h]<br>
     * 可以预计以下结果:<br>
     * ("id", "字符串"),"字符串"分词后有[wwif5,vp3j4l3gj6vn3h]其中之一时,有值。<br>
     * 如:wwIF5-vP3J4l3GJ6VN3h,wwif5-vp3j4l3gj6vn3h,wwIF5,wwif5,wwIF5-6666等等。<br>
     * ("id2", "wwIF5-vP3J4l3GJ6VN3h"),有值。<br>
     * 特别说明:<br>
     * 在创建索引时,如果没有指定"index":"not_analyzed"<br>
     * 会使用默认的analyzer进行分词。当然你可以指定analyzer。<br>
     * 在浏览器中输入:<br>
     * http://localhost:9200/_analyze?pretty&analyzer=standard&text=J4Kz1%26L
     * bvjoQFE9gHC7H<br>
     * 可以看到J4Kz1&LbvjoQFE9gHC7H被分成了:j4kz1和lbvjoqfe9ghc7h<br>

///

*
     * 默认的standard analyzer分词规则:<br>
     * 去掉大部分标点符号,并以此分割原词为多个词,把分分割后的词转为小写放入token组中。<br>
     * 对于not-analyzed的词,直接把原词放入token组中。<br>
     * termQuery的机制是:直接去匹配token。<br>
     * id=id2,默认分词,id2不分词。<br>
     * 以wwIF5-vP3J4l3GJ6VN3h为例:<br>
     * id是的token组是[wwif5,vp3j4l3gj6vn3h]<br>
     * id2的token组是[wwIF5-vP3J4l3GJ6VN3h]<br>
     * 可以预计以下结果:<br>
     * ("id", "wwif5"),有值。<br>
     * ("id", "vp3j4l3gj6vn3h"),有值。<br>
     * ("id2", "wwIF5-vP3J4l3GJ6VN3h"),有值。<br>


总结:match query搜索的时候,首先会解析查询字符串,进行分词,然后查询,而term query,输入的查询内容是什么,就会按照什么去查询,并不会解析查询内容,对它分词。(keyWord).field("FILE_NAME")与matchquery相似