索引的操作

我们建立所有就是要达到快速检索的目的,对数据能够方面便的查找,和数据库类似,索引也有自己的相关增删改查的操作。
在索引的增删改查中,增删改属于写操作,主要是有IndexWrite提供的方法处理;而查显而易见,读操作,使用IndexSeacher 提供的方法来实现。在Lucene的官方文档找到 org.apache.lucene.index.IndexWriter 这个类,我们就可以看到他很多方法。

创建索引

如同上一章里面的代码,创建索引时先建立文件,创建索引的域,再使用IndexWriter的addDocument()方法就可以了,核心代码如下:

iwriter = new IndexWriter(directory, new IndexWriterConfig(version, new StandardAnalyzer(version)));
            for(String text : content){
                doc = new Document();
                //使用的field 有很多类型,理解他们的区别 例如:TextField 和 StringField等
                doc.add(new TextField("content", text,Field.Store.YES));
                iwriter.addDocument(doc);
            }

索引删除

索引删除包括只删除索引下面的document和删除索引文件
在IndexWriter有如下一些方法

  1. deleteAll() 删除索引中所有的documents
  2. deleteDocuments(Query… queries) 按照提供的Query 删除documents
  3. deleteDocuments(Term… terms) 按照短语删除documents
  4. deleteUnusedFiles() 删除所有不再使用index的文件
  5. forceMergeDeletes() 删除处于已经删除的状态documents,由此可见,之前的删除文档的方法并没有真正的删除掉的documents,只是标记删除,我个人理解是类似逻辑上的删除
  6. forceMergeDeletes(boolean doWait) 删除过程中指明是否阻塞,直到操作完成

索引更新

更新操作也是一样,查看文档就有,这里截个图:

索引至左原则_索引至左原则

索引查询

Query
索引查询的时候可以使用Query的实现子类来创建查询,执行IndexSearcher的search方法来查询,也可以使用QueryParse类来构造查询.

分页

  • 方式1:在scoreDoc中进行分页,数据一次性查出来,在结果集分页,结果集较大时容易溢出
  • 方式2:使用searcheAfter,等价查询的次数,但是不会出现查询结果溢出,推荐,类似数据库中的分页查询

这个类似数据库中的查询,可以对结果集分页显示,类似方式一,查询的时候直接分页,类似方式二 。

索引操作实例

package lucene_demo03;

import java.io.IOException;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.ParseException;
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;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;

/**
 * 
 *关于索引的查询(分页查询)
 *方式1:在scoreDoc中进行分页,数据一次性查出来,在结果集分页,结果集较大时容易溢出
 *方式2:使用searcheAfter,等价查询的次数,但是不会出现查询结果溢出,推荐,类似数据库中的分页查询
 * @author YipFun
 */
public class LuceneDemo03 {

    private static final Version version = Version.LUCENE_4_9;
    private Directory directory = null;
    private DirectoryReader ireader = null;
    private IndexWriter iwriter = null;

    //测试数据
    private String[] content = {
        "hello lucene",
        "I love coding",
        "I can play basketball",
        "I can play football",
        "I can play dota"
    };

    /**
     * 构造方法
     */
    public LuceneDemo03() {
        directory = new RAMDirectory();
    }

    /**
     * 创建索引
     */
    public void createIndex(){
        Document doc = null;
        try {
            iwriter = new IndexWriter(directory, new IndexWriterConfig(version, new StandardAnalyzer(version)));
            for(String text : content){
                doc = new Document();
                //使用的field 有很多类型,理解他们的区别 例如:TextField 和 StringField
                doc.add(new TextField("content", text,Field.Store.YES));
                iwriter.addDocument(doc);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            try {
                if(iwriter != null)
                iwriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    public IndexSearcher getSearcher(){
        try {
            if(ireader==null) {
                ireader = DirectoryReader.open(directory);
            } else {
                DirectoryReader tr = DirectoryReader.openIfChanged(ireader) ;
                if(tr!=null) {
                    ireader.close();
                    ireader = tr;
                }
            }
            return new IndexSearcher(ireader);
        } catch (CorruptIndexException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 
     * @param field
     * @param term
     * @param num
     */
    public void searchByTerm(String field,String term,int num){
         IndexSearcher isearcher = getSearcher();
         //注意query的实现类和QueryParse的用法的区别
         TermQuery query = new TermQuery(new Term(field, term));
         ScoreDoc[] hits;
        try {
            //注意searcher的几个方法
            hits = isearcher.search(query, null, num).scoreDocs;
            // Iterate through the results:
            for (int i = 0; i < hits.length; i++) {
              Document hitDoc = isearcher.doc(hits[i].doc);
              System.out.println("This is the text to be indexed="+hitDoc.get("content"));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 区别与上一种查询,使用QueryParser的parse方法构造一个Query传递给方式使用
     * @param query
     * @param num
     */
    public void searchByQueryParse(Query query,int num) {
        try {
            IndexSearcher searcher = getSearcher();
            TopDocs tds = searcher.search(query, num);
            System.out.println("一共查询了:"+tds.totalHits);
            for(ScoreDoc sd:tds.scoreDocs) {
                Document doc = searcher.doc(sd.doc);
                System.out.println("This is the text to be indexed="+doc.get("content"));
            }
        } catch (CorruptIndexException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 第一中分页方式,对ScoreDoc进行分页
     * @param query
     * @param pageIndex 从1开始,即第一页
     * @param pageSize 分页大小
     * @param num search top n hits
     */
    public void searchForPage(Query query ,int pageIndex,int pageSize,int num){
        try {
            IndexSearcher searcher = getSearcher();
            TopDocs tds = searcher.search(query, num);
            System.out.println("一共查询了:"+tds.totalHits);
            //对ScoreDoc分页
            int start = (pageIndex-1)*pageSize;
            int end = pageIndex*pageSize;
            ScoreDoc scoreDocs[] = tds.scoreDocs;
            for(int i=start;i<end;i++) {
                Document doc = searcher.doc(scoreDocs[i].doc);
                System.out.println("This is the text to be indexed="+doc.get("content"));
            }
        } catch (CorruptIndexException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 使用searchAfter 实现在查询的时候的分页
     * @param query 
     * @param pageIndex
     * @param pageSize
     * @throws IOException 
     */
    public void searchForPageByAfter(Query query ,int pageIndex,int pageSize) throws IOException{
        IndexSearcher searcher = getSearcher(); 
        //先获取上一页的最后一个元素
        ScoreDoc lastSd = getLastScoreDoc(pageIndex, pageSize, query, searcher);
        TopDocs tds = searcher.searchAfter(lastSd,query, pageSize);
        for(ScoreDoc sd:tds.scoreDocs) {
            Document doc = searcher.doc(sd.doc);
            System.out.println("This is the text to be indexed="+doc.get("content"));
        }

    }

    /**
     * 返回分页查询的上一条
     * @param pageIndex
     * @param pageSize
     * @param query
     * @param indexSearcher
     * @return
     */
    private ScoreDoc getLastScoreDoc(int pageIndex,int pageSize,Query query,IndexSearcher searcher){
        if(pageIndex==1)return null;//如果是第一页就返回空
        int num = pageSize*(pageIndex-1);//获取上一页的数量
        TopDocs tds = null;
        try {
            tds = searcher.search(query, num);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return tds.scoreDocs[num-1];
    }


    public static void main(String[] args) throws ParseException, IOException {
        LuceneDemo03 ld = new LuceneDemo03();
        ld.createIndex();
        ld.searchByTerm("content","play",500);
        System.out.println("==============1======================");

        QueryParser parser = new QueryParser(version, "content", new StandardAnalyzer(version));
        Query q = parser.parse("play");//研究下parse的语法
        ld.searchByQueryParse(q,500);
        System.out.println("===============2=====================");

        ld.searchForPage(q, 1, 2, 500);//从第一页开始
        System.out.println("================3====================");

        ld.searchForPageByAfter(q, 1, 2);//从第一页开始
        System.out.println("================4====================");
    }



}