3.创建和维护索引库(Lucene6.0.0 CRUD)

项目源码:https://github.com/tangxing1993/lucene

3.1 创建和更新索引

Lucene给我们提供了创建和更新索引的API,在生成索引的过程中涉及到以下几个类。
IndexWriter>Document>Field>Analyzer
Field 域对象,存在与文档内。通用接口IndexField,field是一个抽象域对象。StringField不分词完全存入到索引库中,TextField 进行分词,并且索引

创建索引

索引一般存放在硬盘的某个路径下,我们可以使用IndexWriter来创建一个索引库,IndexWriter对象的相关参数有:索引路径和配置信息,创建完索引库后要把索引文档放入到索引库中,索引文档包含要索引的域信息。
    /**
     * 创建索引
     */
    public void createIndex(){
        long startTime = System.currentTimeMillis(); //索引的创建时间
        System.out.println("start index ... ");
        IndexWriter writer = null;
        Document document = null;
        try{
            IndexWriterConfig config = new IndexWriterConfig(analyzer);
            writer  = new IndexWriter(directory, config);
            writer.deleteAll();
            /**
             * 这里为了提高索引的速度,我们重用field对象,而不是每次创建新的,可以节省GC的消耗时间
             * Field是intPoint/StringField/TextField/longPoint等的父类 
             * 我们可以根据数据类型的需要选择合适的field对象
             */
            IntPoint iPoint = new IntPoint("id", 0);
            StringField sField = new StringField("name","", Store.YES);
            TextField tField = new TextField("content", "", Store.YES);
            LongPoint lPoint = new LongPoint("date", 0);
            for(int i=0;i<ids.length;i++){
                document = new Document();
                iPoint.setIntValue(ids[i]);
                document.add(iPoint);
                sField.setStringValue(names[i]);
                document.add(sField);
                tField.setStringValue(contents[i]);
                document.add(tField);
                lPoint.setLongValue(dates[i].getTime());
                document.add(lPoint);
                writer.addDocument(document);
            }
        long endTime = System.currentTimeMillis();//索引的结束时间
        System.out.println("end index !!!");
        System.out.println("times:"+(endTime-startTime)+"ms");
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            if(null!=writer){
                try {
                    writer.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

执行结果
索引内容

更新索引

Lucene更新索引文档是先删除旧的文档信息,然后把新的文档写入到索引库中。用到的方法是IndexWriter.updateDocument,传入的参数为term,要删除的文档term信息,第二个参数为新的文档信息
    /**
     * 更新索引对象  早期的版本中先通过IndexReader删除文档 再使用IndexWriter写入更新后的文档
     * 新版本中我们可以通过先查找出要修改的旧文档,然后改变要改动的列,最后updateDocument
     */
    public void updateIndex(){
        IndexWriter writer = null;
        Document document = null;
        try{
            System.out.println("开始更新...");
            writer = new IndexWriter(directory,new IndexWriterConfig(analyzer));
            IndexSearcher search = new IndexSearcher(this.getIndexReader());
            Query query = new QueryParser("name", analyzer).parse("aa");
            TopDocs topDocs = search.search(query, 10);
            ScoreDoc[] scoreDocs = topDocs.scoreDocs;
            if(scoreDocs.length==0){
                throw new IllegalArgumentException("索引中没有匹配结果...");
            }else if(scoreDocs.length>1){
                throw new IllegalArgumentException("索引匹配多个结果...");
            }else{
                //获取旧文档
                document = search.doc(scoreDocs[0].doc);
                //先删除要改变的旧列
                document.removeFields("name");
                document.add(new StringField("name","update",Store.YES));
                //term是搜索语法的最小单位    这里的更新是先删除在更新  删除的对象放在索引回收站里面   数据还可以恢复
                writer.updateDocument(new Term("name","aa"), document);
            }
            System.out.println("文档更新成功!");
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            if(null!=writer){
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

效果展示:
luke看到索引内部已经更新
文档先删除后添加

索引库的删除

lucene使用IndexWriter来删除索引文档
    public void delete(){
    IndexWriter writer =null; 
    try{
        writer = new IndexWriter(directory, new IndexWriterConfig(analyzer));
        //TermQuery  精确的查询方法
        writer.deleteDocuments(new TermQuery(new Term("name", "bb")));
    }catch(Exception e){
         e.printStackTrace();
    }finally{
        if(null!=writer){
            try {
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    }

效果展示:
bb文档已经被删除了

简单的索引查询

Lucene使用IndexSearch来执行查询的所有操作,需要参数:索引库的字符流对象。lucene运用search方法查询出具有相关度的数据,然后我们按照评分取出。TopDocs具有相关度的文档,ScoreDocs文档评分数组
    public void doSearch(){
        IndexSearcher search = null;
        try{
            search = new IndexSearcher(this.getIndexReader());
            //创建查询解析器
            QueryParser parse = new QueryParser("content", analyzer);
            //获取查询对象
            Query query = parse.parse("like");
            //搜索索引库返回最相关的10条数据
            TopDocs topDocs = search.search(query, 10);//第二个参数为搜索显示的记录数
            //从topDocs中取出查询结果
            ScoreDoc[] sds = topDocs.scoreDocs;
            for(ScoreDoc sd : sds){
                //获取结果文档信息
                Document doc = search.doc(sd.doc);
                System.out.println("docID:"+sd.doc+" | id:"+doc.get("id")+" | "
                        + "name:"+doc.get("name")+" | content:"+doc.get("content")+" | date:"+doc.get("date"));
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }

结果:
这里写图片描述
通过结果发现。使用IntPoint和LongPoint并没有把数据存放到索引库中,所以查询到的结果为null

Field总结

IntPoint

索引int类型的值不存储不排序

FloatPoint

索引float类型的值不存储不排序

DoublePoint

索引Double类型的值不存储不排序

BinaryDocValuesField

只存储不共享,例如标题类字段,如果需要共享并排序,推荐使用

NumericDocValuesField

存储long型字段,用于评分、排序和值检索,如果需要存储值,还需要添加一个单独的StoredField实例

SortedDocValuesField

索引并存储,用于String类型的Field排序,需要在StringField后添加同名的SortedDocValuesField

StringField

只索引但不分词,所有的字符串会作为一个整体进行索引,例如通常用于country或id等

TextField

索引并分词,不包括term vectors,例如通常用于一个body Field

StoredField

存储Field的值,可以用 IndexSearcher.doc和IndexReader.document来获取存储的Field和存储的值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值