lucene全文检索的 增、删、改 简单操作案例

本文介绍如何使用Lucene实现简单的数据增删改查操作,并提供完整的代码示例,包括构建索引、检索文档、更新及删除索引等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

针对lucene全文检索引擎写一个简单的增删改的案例

这里采用的是英文分词,单独写了一篇关于中文分词与高亮显示,如下:
lucene全文检索之 中文分词 以及 高亮显示,点击进入

另外分享一个 lucene索引库查看器 ,点击进入

lucene官网 http://lucene.apache.org

首先需要引入lucene的maven依赖,如下:

<dependency>
    <groupId>org.apache.lucene</groupId>
    <artifactId>lucene-core</artifactId>
    <version>5.3.1</version>
</dependency>

<dependency>
    <groupId>org.apache.lucene</groupId>
    <artifactId>lucene-queryparser</artifactId>
    <version>5.3.1</version>
</dependency>

<dependency>
    <groupId>org.apache.lucene</groupId>
    <artifactId>lucene-analyzers-common</artifactId>
    <version>5.3.1</version>
</dependency>

然后就可以开始了,代码如下:

package luceneDemo;

import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.Directory;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;

/**
 * 全文检索案例
 * @author mszhou
 */
public class luceneTest {

    /**
     * 演示将数据写入索引文件中
     * 在项目中我们会定时将数据写入索引文件中,
     * 然后在索引文件中进行搜索,这样比在数据库中搜索效率高的多,
     * 而且检索远比数据库的模糊匹配强大的多,这也是检索工具牛逼之处
     * 需要注意的是,如果在项目中定时写入索引,
     * 需要判断下该数据是否存在,存在则修改,不存在再进行新增
     * 
     * @param luceneDir 该参数表示索引所存放的目录
     */
    public static void writeIndex(String luceneDir){
        IndexWriter writer = null;//声明创建索引写入器 
        try{
            //创建索引目录 , 这里参数luceneDir 表示索引存放目录
            Directory dir=FSDirectory.open(Paths.get(luceneDir));

            //创建标准分词器(一般英文使用这个,不适合中文使用)
            Analyzer analyzer=new StandardAnalyzer(); // 标准分词器

            IndexWriterConfig iwc=new IndexWriterConfig(analyzer);

            //创建索引写入器实例,通过IndexWriterConfig设置相关配置
            writer=new IndexWriter(dir, iwc);


            //=== 这里造一些数据用作演示,也可以直接读取数据库中的数据 开始========
            List <Map<String,String>> list=new ArrayList<Map<String,String>>();

            //假数据1 
            Map<String,String> map1 =new HashMap<String, String>();
            map1.put("id", "1");//表示id字段,这里id用String类型了,大家可以用int
            map1.put("title", "weejij dasa ");//表示标题字段
            map1.put("centent", "hdaiads sd s g r44e r hgg f hd 4 ");//表示标题字段
            list.add(map1);

            //假数据2 
            Map<String,String> map2 =new HashMap<String, String>();
            map2.put("id", "2");//表示id字段,这里id用String类型了,大家可以用int
            map2.put("title", "demo is ss");//表示标题字段
            map2.put("centent", "hdaiads sd s g r44e r hgg f hd 4 ");//表示标题字段   
            list.add(map2);

            //假数据1 
            Map<String,String> map3 =new HashMap<String, String>();
            map3.put("id", "3");//表示id字段,这里id用String类型了,大家可以用int
            map3.put("title", "demo is ss");//表示标题字段
            map3.put("centent", "hdaiads sd s g r44e r hgg f hd 4 ");//表示标题字段   
            list.add(map3);
            //=== 这里造一些数据用作演示,也可以直接读取数据库中的数据 结束========

            //遍历数据,并且将数据写入到索引中
            for(Map<String,String> mapCen : list){
                // ======   获取数据开始 ====== 
                String id =mapCen.get("id").toString();//获取id 
                String title =  mapCen.get("title").toString();//获取标题
                String centent = mapCen.get("centent").toString();//获取内容
                // ======   获取数据结束 ====== 

                //========= 将数据写入索引开始  =================
                //创建Document对象,Document表示lucene索引的数据结构单元
                Document doc=new Document();
                //添加id 数据,最后面Field.Store.YES表示存储该字段
                doc.add(new StringField("id",id, Field.Store.YES));

                /*添加标题数据,最后面Field.Store.YES 表示存储该字段
                 *注意:如果需要检索该字段,建议使用TextField类型,并且设置为 Field.Store.YES
                 */
                doc.add(new TextField("title",title , Field.Store.YES));
                //添加标题内容数据,最后面Field.Store.NO  表示不存储该字段
                doc.add(new TextField("centent", centent, Field.Store.NO));

                // 写入索引
                writer.addDocument(doc); 
                //========= 将数据写入索引结束  =================
            }
        }catch(Exception e){
            System.out.println("发生了异常!");
            e.printStackTrace();
        }finally{
            try {
                writer.close();//关闭流,一定要记得关闭
            } catch (IOException e) {
            }
        }
    }

    /**
     * 演示删除索引文档数据 
     * 
     * @param luceneDir 该参数表示索引所存放的目录
     */
    public static void testDelete(String luceneDir){
        IndexWriter writer = null;//声明创建索引写入器 
        try{
            //创建索引目录 , 这里参数luceneDir 表示索引存放目录
            Directory dir=FSDirectory.open(Paths.get(luceneDir));

            //创建标准分词器(一般英文使用这个,不适合中文使用)
            Analyzer analyzer=new StandardAnalyzer(); // 标准分词器

            IndexWriterConfig iwc=new IndexWriterConfig(analyzer);

            //创建索引写入器 ,通过IndexWriterConfig设置相关配置
            writer=new IndexWriter(dir, iwc);

            //打印索引实际文档数
            System.out.println("删除前:"+writer.numDocs());

            /*删除属性字段id为1的文档数据,就是上面写入的第一条测试数据,如下
             * map1.put("id", "1");//表示id字段,这里id用String类型了,大家可以用int
             * map1.put("title", "weejij dasa ");//表示标题字段
             * map1.put("centent", "hdaiads sd s g r44e r hgg f hd 4 ");//表示标题字
             */
            writer.deleteDocuments(new Term("id","1"));

            /*
             * 调用该方法强制已删除文档中的所有段合并,
             * 需要注意的是如果不调用该方法,则删除后实际文件数还是跟删除之前的一样
             * 因为还没有合并,在项目中如果数据量比较大,
             * 我们可以定时调用该方法来强制合并删除的数据
             */
            writer.forceMergeDeletes(); // 强制删除

            writer.commit();//提交

            //打印索引实际文档数
            System.out.println("删除后:"+writer.numDocs());
        }catch(Exception e){
            System.out.println("发生了异常!");
            e.printStackTrace();
        }finally{
            try {
                writer.close();//关闭流,一定要记得关闭
            } catch (IOException e) {
            }
        }
    }


    /**
     * 演示更新索引文档数据 
     * 
     * @param luceneDir 该参数表示索引所存放的目录
     */
    public static void testUpdate(String luceneDir){

        IndexWriter writer = null;//声明创建索引写入器 
        try{
            //创建索引目录 , 这里参数luceneDir 表示索引存放目录
            Directory dir=FSDirectory.open(Paths.get(luceneDir));

            //创建标准分词器(一般英文使用这个,不适合中文使用)
            Analyzer analyzer=new StandardAnalyzer(); // 标准分词器

            IndexWriterConfig iwc=new IndexWriterConfig(analyzer);

            //创建索引写入器 ,通过IndexWriterConfig设置相关配置
            writer=new IndexWriter(dir, iwc);

            //========= 这里造一条需要更新的假数据开始============
            Document doc=new Document();
            //设置数据id 数据,最后面Field.Store.YES表示存储该字段
            doc.add(new StringField("id", "2", Field.Store.YES));
            //设置标题数据,最后面Field.Store.YES 表示存储该字段
            doc.add(new StringField("title","dewef sdasa",Field.Store.YES));
            //设置标题内容数据,最后面Field.Store.NO  表示不存储该字段
            doc.add(new TextField("centent", "fdfds fdddf fs sa", Field.Store.NO));
            //========= 这里造一条需要更新的假数据结束  ============

            //更新属性字段id为2的文档数据,
            writer.updateDocument(new Term("id","2"), doc);

        }catch(Exception e){
            System.out.println("发生了异常!");
            e.printStackTrace();
        }finally{
            try {
                writer.close();//关闭流,一定要记得关闭
            } catch (IOException e) {
            }
        }   
    }

    /**
     * 演示获取索引文档的数量
     * @param luceneDir 该参数表示索引所存放的目录
     * @return 返回索引文档数量
     */
    public static int getIndexCount(String luceneDir){
        IndexWriter writer = null;//声明创建索引写入器 
        int count =0;//用看来保存索引文件的数量
        try{

            //创建索引目录 , 这里参数luceneDir 表示索引存放目录
            Directory dir=FSDirectory.open(Paths.get(luceneDir));

            //创建标准分词器(一般英文使用这个,不适合中文使用)
            Analyzer analyzer=new StandardAnalyzer(); // 标准分词器

            IndexWriterConfig iwc=new IndexWriterConfig(analyzer);

            //创建索引写入器 ,通过IndexWriterConfig设置相关配置
            writer=new IndexWriter(dir, iwc);

            count = writer.numDocs();//获取索引文件的个数

            System.out.println("有"+count+"个文档");
        }catch(Exception e){
            System.out.println("发生了异常!");
            e.printStackTrace();
        }finally{
            try {
                writer.close();//关闭流,一定要记得关闭
            } catch (IOException e) {
            }
        }
        return count;
    }

    /**
     *  演示读取文档
     *  @param luceneDir 该参数表示索引所存放的目录
     */
    public static void readerIndexCount(String luceneDir){
        IndexReader reader = null;//声明索引读取器
        try{
            //创建索引目录 , 这里参数luceneDir 表示索引存放目录
            Directory dir=FSDirectory.open(Paths.get(luceneDir));
            //创建索引读取器
            reader=DirectoryReader.open(dir);
            //打印信息
            System.out.println("最大文档数:"+reader.maxDoc());
            System.out.println("实际文档数:"+reader.numDocs());
        }catch(Exception e){
            System.out.println("发生了异常!");
            e.printStackTrace();
        }finally{
            try {
                reader.close();//关闭流,一定要记得关闭
            } catch (IOException e) {
            }
        }
    }





    /**
     * 演示简单检索匹配一下标题title字段的数据
     * @param luceneDir 该参数表示索引所存放的目录
     * @param titleStr 需要检索的关键词
     */
    public static void search(String luceneDir,String titleStr){

        IndexReader reader = null;//声明索引读取器
        try{
            //创建索引目录 , 这里参数luceneDir 表示索引存放目录
            Directory dir=FSDirectory.open(Paths.get(luceneDir));
            //创建索引读取器
            reader=DirectoryReader.open(dir);

            //创建索引搜索器
            IndexSearcher is=new IndexSearcher(reader);

            //创建标准分词器(一般英文使用这个,不适合中文使用)
            Analyzer analyzer=new StandardAnalyzer(); // 标准分词器

            //创建QueryParser查询器,查询title属性字段
            QueryParser parser=new QueryParser("title", analyzer);
            //设置查询关键词
            Query query=parser.parse(titleStr);

            //这里查询前10条匹配的数据,第二个参数为10表示查前十条
            TopDocs hits=is.search(query, 10);

            //打印信息
            System.out.println("匹配 "+titleStr+" , 查询到"+hits.totalHits+"个记录");

            //遍历查询到的数据
            for(ScoreDoc scoreDoc:hits.scoreDocs){
                Document doc=is.doc(scoreDoc.doc);
                String id  = doc.get("id").toString();//获取id
                String title  = doc.get("title").toString();//获取标题

                //由于写入的时候 ,设置了Field.Store.NO 表示不存储该字段,所以这里读取不到
                //String centent  = doc.get("centent").toString();//获取内容

                //打印数据
                System.out.println("id是:"+id+" ,标题是:"+title);
            }
        }catch(Exception e){
            System.out.println("发生了异常!");
            e.printStackTrace();
        }finally{
            try {
                reader.close();//关闭流,一定要记得关闭
            } catch (IOException e) {
            }
        }
    }


    /**
     * 测试上面的方法
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {

        //表示索引目录
        String luceneDir =  "D://lucene";

        //测试该方法写入数据到索引文件中
        //writeIndex(luceneDir);

        //测试该方法获取索引文件数量
        //int count = getIndexCount(luceneDir);

        //测试该方法打印索引最大文档与实际文档数
        //readerIndexCount(luceneDir);

        //测试该方法删除索引文档数据
        //testDelete(luceneDir);

        //测试该方法更新索引文档数据
        //testUpdate(luceneDir);

        //测试该方法检索询
        search(luceneDir,"demo");

    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值