Lucene 全文索引

pom.xml配置

    <!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-core -->
    <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-core</artifactId>
        <version>7.6.0</version>
    </dependency>
    <!-- 检索关键字高亮显示 -->
    <!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-highlighter -->
    <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-highlighter</artifactId>
        <version>7.6.0</version>
    </dependency>
    <!-- 与查询比较的高性能单文档索引 高亮显示需要此jar -->
    <!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-memory -->
    <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-memory</artifactId>
        <version>7.6.0</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-queryparser -->
    <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-queryparser</artifactId>
        <version>7.6.0</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-demo -->
    <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-demo</artifactId>
        <version>7.6.0</version>
    </dependency>
    <!-- 一般分词器,适用于英文分词 -->
    <!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-analyzers-common -->
    <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-analyzers-common</artifactId>
        <version>7.6.0</version>
    </dependency>
    <!-- 中文分词器 -->
    <!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-analyzers-smartcn -->
    <dependency>
        <groupId>org.apache.lucene</groupId>
        <artifactId>lucene-analyzers-smartcn</artifactId>
        <version>7.6.0</version>
    </dependency>
    <!--编码转换 -->
    <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.4</version>
    </dependency>

方法使用

public class Lucene extends BaseExtController {
    private static final Logger log = Logger.getLogger(Lucene.class);
    final String filePath = PropKit.use("config.properties").get("lucenePath","");

    /**
     * 创建并在指定的位置写入lucene索引文件
     * @创建时间:2021年09月09日
     *
     * filePath:
     *         索引库的位置
     * luceneManagerList:
     *          创建索引数据集合
     */
    public void createIndex(List<LuceneManager> luceneManagerList) throws IOException {

        log.info("存储索引数据长度_"+luceneManagerList.size());
        IndexWriter writer = null;
        // 定义一个Document集合
        List<Document> documents = new ArrayList();
        // 定义document对象
        Document document;

        // 遍历查询出来的数据
        for (LuceneManager lucene : luceneManagerList) {
            // 实例化document对象
            document = new Document();

            if (!StrKit.isBlank(lucene.getId())){
                // 不进行分词,只进行索引、存储
                Field id = new StringField("id", lucene.getId(), Field.Store.YES);
                // 将Field放到document对象中
                document.add(id);
            }
            if (!StrKit.isBlank(lucene.getSid())){
                // 不进行分词,只进行索引、存储
                Field sid = new StringField("sid", lucene.getSid(), Field.Store.YES);
                // 将Field放到document对象中
                document.add(sid);
            }
            if (!StrKit.isBlank(lucene.getTitle())){
                // 进行分词、索引、存储
                Field title = new TextField("title", lucene.getTitle(), Field.Store.YES);
                document.add(title);
            }
            if (!StrKit.isBlank(lucene.getAbs())){
                // 进行分词、索引、存储
                Field abs = new TextField("abs", lucene.getAbs(), Field.Store.YES);
                document.add(abs);
            }
            if (!StrKit.isBlank(lucene.getDesc())){
                // 进行分词、索引、存储
                Field desc = new TextField("desc", lucene.getDesc(), Field.Store.YES);
                document.add(desc);
            }
            if (!StrKit.isBlank(lucene.getType())){
                // 不进行分词、索引,只存储
                Field type = new TextField("type", lucene.getType(), Field.Store.YES);
                document.add(type);
            }
            if (!StrKit.isBlank(lucene.getTime())){
                // 不进行分词、索引,只存储
                Field time = new TextField("time", lucene.getTime(), Field.Store.YES);
                document.add(time);
            }
            if (!StrKit.isBlank(lucene.getImg())){
                // 不进行分词、索引,只存储
                Field img = new StoredField("img", lucene.getImg());
                document.add(img);
            }
            if (!StrKit.isBlank(lucene.getTableName())){
                // 不进行分词、索引,只存储
                Field tableName = new StoredField("tableName", lucene.getTableName());
                document.add(tableName);
            }
            if (!StrKit.isBlank(lucene.getRemarks())){
                // 不进行分词、索引,只存储
                Field remarks = new StoredField("remarks", lucene.getRemarks());
                document.add(remarks);
            }

            // 将document放到documents集合中
            documents.add(document);
        }

        // 创建一个标准分词对象
        Analyzer analyzer = new StandardAnalyzer();
        // 索引库的位置
        Directory directory = FSDirectory.open(FileSystems.getDefault().getPath(filePath));
        // 索引序列化的配置
        IndexWriterConfig config = new IndexWriterConfig(analyzer);
        try {
            // 创建索引序列化(写入流)对象
            writer = new IndexWriter(directory, config);

            // 将documents对象循环写入到指定的索引目录 中
            for (Document doc : documents) {
                writer.addDocument(doc);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            // 关闭流对象
            writer.close();
        }

        log.info("存储索引数据成功");
    }

    /**
     * 通过指定的lucene索引目录查询指定的数据
     * searchContent:
     *          搜索条件
     * searchName:
     *          检索类型,可以为空,默认检索题目和摘要
     * page_no:
     *          数据页码,可以为空,默认查询1条
     * page_size:
     *          数据分页,可以为空,默认查询10条
     *
     */
    public Page<Record> readerIndex(String searchName, String searchContent, Integer page_no, Integer page_size) throws ParseException, IOException {

        log.info("搜索数据字段____"+searchName+"---"+searchContent);
        IndexReader reader = null;
        List<LuceneManager> dataList = new ArrayList();
        MultiFieldQueryParser queryParser = null;
        if (StrKit.isBlank(searchName)){//未传入搜索类型,默认,搜索题目和摘要
            String[] fields = {"title","abs"};
            // 创建QueryParser对象,并指定要查询的索引域及分词对象
            queryParser = new MultiFieldQueryParser(fields, new StandardAnalyzer());
        }else {//传入搜索类型,以搜索类型为主进行检索
            String[] fields = {};
            if (searchName.contains(",")){
                String[] split = searchName.split(",");
                fields = new String[split.length];
                for (int i = 0; i < split.length; i++) {
                    fields[i]=split[i];
                }
            }else {
                fields = new String[]{searchName};
            }
            // 创建QueryParser对象,并指定要查询的索引域及分词对象
            queryParser = new MultiFieldQueryParser(fields, new StandardAnalyzer());
        }
        // 创建Query对象,指定查询条件
        Query query = queryParser.parse(searchContent);
        // 指定要查询的lucene索引目录,必须与存储的索引目录一致
        Directory directory = FSDirectory.open(FileSystems.getDefault().getPath(filePath));
        com.jfinal.plugin.activerecord.Page<Record> page = null;

        // 格式化器
        Formatter formatter = new SimpleHTMLFormatter("<highLight>", "</highLight>");
        Scorer scorer = new QueryScorer(query);
        // 准备高亮工具
        Highlighter highlighter = new Highlighter(formatter, scorer);

        try {
            // 通过指定的查询目录文件地址创建IndexReader流对象
            reader = DirectoryReader.open(directory);
            // 通过IndexReader流对象创建IndexSearcher
            IndexSearcher searcher = new IndexSearcher(reader);

            TopDocs search = searcher.search(query, page_size * page_no + 1);

            // 获取查询关键字获得的数据总数
            long totalHits = search.totalHits;
            log.info("通过查询条件总共查询到的数据量为:" + totalHits);

            // 获取查询到的数据
            ScoreDoc[] scoreDocs = search.scoreDocs;

            int totalPage = page_no+1;
            int totalRow =  scoreDocs.length;
            if (totalRow <= page_size * page_no){
                totalPage = page_no;
            }

            for (int i = (page_no-1)*page_size; i < scoreDocs.length; i++) {

                int docId = scoreDocs[i].doc;

                LuceneManager luceneManager = new LuceneManager();
                // 根据索引查询数据
                Document document = searcher.doc(docId);

                // 查询到的数据
                luceneManager.setId(document.get("id"));
                luceneManager.setSid(document.get("sid"));
//                luceneManager.setTitle(document.get("title"));

                // 用高亮工具处理普通的查询结果,参数:分词器,要高亮的字段的名称,高亮字段的原始值
                String title = highlighter.getBestFragment(new StandardAnalyzer(), "title", document.get("title"));
                if (StrKit.notBlank(title) && title.length()>0){
                    luceneManager.setTitle(title);
                }else {
                    luceneManager.setTitle(document.get("title"));
                }


                String abs = highlighter.getBestFragment(new StandardAnalyzer(), "abs", document.get("abs"));
                if (StrKit.notBlank(abs) && abs.length()>0){
                    luceneManager.setAbs(abs);
                }else {
                    luceneManager.setAbs(document.get("abs"));
                }

//                luceneManager.setAbs(document.get("abs"));
                luceneManager.setDesc(document.get("desc"));
                luceneManager.setImg(document.get("img"));
                luceneManager.setTime(document.get("time"));
                luceneManager.setType(document.get("type"));
                luceneManager.setRemarks(document.get("remarks"));
                luceneManager.setTableName(document.get("tableName"));

                dataList.add(luceneManager);
            }

            page = new com.jfinal.plugin.activerecord.Page(dataList, page_no, page_size, totalPage, totalRow);

        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            // 关闭流
            reader.close();
        }

        return page;
    }

    /**
     * 根据查询条件删除lucene索引及文档数据
     * */
    public void deleteIndex(String name,String value) throws IOException, ParseException {

        IndexWriter writer = null;
        try {
            // 创建分词对象
            Analyzer analyzer = new StandardAnalyzer();
            // 指定lucene索引目录地址
            Directory directory = FSDirectory.open(FileSystems.getDefault().getPath(filePath));
            // 创建配置对象
            IndexWriterConfig config = new IndexWriterConfig(analyzer);
            // 通过指定的索引目录地址、配置对象创建IndexWriter流对象
            writer = new IndexWriter(directory, config);
            // 删除索引目录的数据
            writer.deleteDocuments(new Term(name, value));
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            // 关闭流对象
            writer.close();
        }


    }

    /**
     * 删除全部lucene索引及文档数据
     * */
    public void deleteAllIndex() throws IOException, ParseException {

        IndexWriter writer = null;
        try{
            // 创建分词对象
            Analyzer analyzer = new StandardAnalyzer();
            // 指定lucene索引目录地址
            Directory directory = FSDirectory.open(FileSystems.getDefault().getPath(filePath));
            // 创建配置对象
            IndexWriterConfig config = new IndexWriterConfig(analyzer);
            // 通过指定的索引目录地址、配置对象创建IndexWriter流对象
            writer = new IndexWriter(directory, config);

            // 清空索引及存档的所有数据
            writer.deleteAll();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            // 关闭流对象
            writer.close();
        }

    }

    /* *
     * 更新索引
     * */
    public void updateIndex(String name,String newValue,String oldValue) throws IOException, ParseException {

        IndexWriter writer = null;
        try {
            //创建分词对象
            Analyzer analyzer = new StandardAnalyzer();
            //指定索引目录地址
            Directory directory = FSDirectory.open(FileSystems.getDefault().getPath(filePath));
            //创建配置对象
            IndexWriterConfig config = new IndexWriterConfig(analyzer);
            //通过配置、目录参数创建流对象
            writer = new IndexWriter(directory, config);

            //创建document对象
            Document doc = new Document();
            //添加索引数据到doc对象
            /*doc.add(new TextField("id", "7", Store.YES));
            //将新添加的doc数据替换索引中已经有的id为2的数据
            //执行步骤如下:查询数据--》查询到或未查询到--》替换/添加doc数据
            writer.updateDocument(new Term("id", "2"), doc);*/
            doc.add(new TextField(name, newValue, Field.Store.YES));
            writer.updateDocument(new Term(name, oldValue), doc);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            // 关闭流对象
            writer.close();
        }

    }

    public List<LuceneManager> queryIndex(String name,String value) throws IOException, ParseException {

        IndexReader reader = null;
        List<LuceneManager> dataList = new ArrayList();
        try {
            Analyzer analyzer = new StandardAnalyzer();
            // 创建指定查询域、分词对象创建QueryParser对象
            QueryParser parser = new QueryParser(name, analyzer);
            // 指定查询条件,创建query对象
            Query query = parser.parse(new StringBuilder(name + ":").append(value).toString());
            Directory directory = FSDirectory.open(FileSystems.getDefault().getPath(filePath));
            // 创建reader流对象,打开指定的lucene索引目录
            reader = DirectoryReader.open(directory);
            // 通过创建的流对象创建查询对象searcher
            IndexSearcher searcher = new IndexSearcher(reader);
            // 通过查询对象查询指定条件的数据
            TopDocs topDocs = searcher.search(query, 100);
            // 获取查询的数据总量
            long totalHits = topDocs.totalHits;
            // 将查询返回的索引数据赋值给scoreDocs对象
            ScoreDoc[] scoreDocs = topDocs.scoreDocs;

            // 如果查询的数据不存在,输出提示信息
            if (scoreDocs == null || scoreDocs.length == 0) {
                log.info("未查询到" + name + "为" + value + "的数据,删除" + name + "为" + value + "的数据成功");
            } else {
                // 如果查询的数据未删除成功,则输出相应的数据
                for (ScoreDoc doc : scoreDocs) {
                    // 获取查询到的索引id
                    int docId = doc.doc;
                    // 通过查询到的索引id查询索引中对应的文档域中的内容
                    Document document = searcher.doc(docId);

                    LuceneManager luceneManager = new LuceneManager();
                    // 输出查询到的数据
                    luceneManager.setId(document.get("id"));
                    luceneManager.setSid(document.get("sid"));
                    luceneManager.setTitle(document.get("title"));
                    luceneManager.setAbs(document.get("abs"));
                    luceneManager.setDesc(document.get("desc"));
                    luceneManager.setImg(document.get("img"));
                    luceneManager.setTime(document.get("time"));
                    luceneManager.setType(document.get("type"));
                    luceneManager.setRemarks(document.get("remarks"));
                    luceneManager.setTableName(document.get("tableName"));

                    dataList.add(luceneManager);
                }
            }

        } catch (Exception e){
            e.printStackTrace();
        }finally {
            // 关闭流对象
            reader.close();
        }

        return dataList;
    }

}

实体类(根据具体需求修改)

public class LuceneManager implements Serializable {

    private static final long serialVersionUID = 1;
    private String id;
    private String sid;//随机id
    private String title;//标题
    private String desc;//文章
    private String time;//时间
    private String img;//图片url
    private String abs;//摘要
    private String type;//类型
    private String tableName;//表名存储,用于表区分
    private String remarks;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getSid() {
        return sid;
    }

    public void setSid(String sid) {
        this.sid = sid;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }

    public String getImg() {
        return img;
    }

    public void setImg(String img) {
        this.img = img;
    }

    public String getAbs() {
        return abs;
    }

    public void setAbs(String abs) {
        this.abs = abs;
    }

    public String getRemarks() {
        return remarks;
    }

    public void setRemarks(String remarks) {
        this.remarks = remarks;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getTableName() {
        return tableName;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName;
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值