zoukankan      html  css  js  c++  java
  • Lucene基础(二)--索引的操作

    索引的操作

    我们建立所有就是要达到快速检索的目的,对数据能够方面便的查找,和数据库类似,索引也有自己的相关增删改查的操作。 
    在索引的增删改查中,增删改属于写操作,主要是有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====================");
      }

    }

  • 相关阅读:
    逻辑学的基本运算
    第一性原理:First principle thinking是什么?
    人类认识的基本技能
    编程的本质:简化+抽象+再现
    区块链
    信号、系统、传递、树
    MVVM
    数据驱动 状态驱动
    事件与状态机 事件驱动编程
    数据一致性举例:登录系统
  • 原文地址:https://www.cnblogs.com/downey/p/4890789.html
Copyright © 2011-2022 走看看