索引的维护、优化、创建过程、逻辑结构

  索引维护

管理人员通过电商系统更改图书信息,这时更新的是数据库,如果使用lucene搜索图书信息需要在数据库表book信息变化时及时更新lucene索引库。

调用indexWriter.addDocument(doc)添加索引,参考入门程序的创建索引。

 1、删除索引(根据Term删除索引,满足条件的将全部删除。)

// 删除索引

     @Test

     publicvoid deleteIndex() throws Exception {

         // 1、指定索引库目录

         Directory directory = FSDirectory.open(new File("E:\\11-index\\0720"));

         // 2、创建IndexWriterConfig

         IndexWriterConfig cfg = new IndexWriterConfig(Version.LATEST,

                   new StandardAnalyzer());

         // 3、创建IndexWriter

         IndexWriter writer = new IndexWriter(directory, cfg);

         // 4、通过IndexWriter来删除索引

         // b)、删除指定索引

         writer.deleteDocuments(new Term("filename""apache"));

         //删除的是一个document对象

         // 5、关闭IndexWriter

         writer.close();

     }

2、删除全部索引(慎用)(将索引目录的索引信息全部删除,直接彻底删除,无法恢复。慎用!!!)

// 删除索引

     @Test

     publicvoid deleteIndex() throws Exception {

         // 1、指定索引库目录

         Directory directory = FSDirectory.open(new File("E:\\11-index\\0720"));

         // 2、创建IndexWriterConfig

         IndexWriterConfig cfg = new IndexWriterConfig(Version.LATEST,

                   new StandardAnalyzer());

         // 3、创建IndexWriter

         IndexWriter writer = new IndexWriter(directory, cfg);

         // 4、通过IndexWriter来删除索引

         // a)、删除全部索引

         writer.deleteAll();

         // 5、关闭IndexWriter

         writer.close();

     }

建议参照关系数据库基于主键删除方式,所以在创建索引时需要创建一个主键Field,删除时根据此主键Field删除。

索引删除后将放在Lucene的回收站中,Lucene3.X版本可以恢复删除的文档,3.X之后无法恢复。

3、修改索引

更新索引是先删除再添加,建议对更新需求采用此方法并且要保证对已存在的索引执行更新,可以先查询出来,确定更新记录存在执行更新操作。

      /**

      * 参数1:指定更新条件,id1的更新为新文档对象

      * 参数2:修改后的文档对象

      * 更新流程:查询:有索引>删索引>增索引>覆盖新的文档对象

      *              无索引>增索引

      */

     // 修改索引

     @Test

     publicvoid updateIndex() throws Exception {

         // 1、指定索引库目录

         Directory directory = FSDirectory.open(new File("E:\\11-index\\0720"));

         // 2、创建IndexWriterConfig

         IndexWriterConfig cfg = new IndexWriterConfig(Version.LATEST,

                   new StandardAnalyzer());

         // 3、创建IndexWriter

         IndexWriter writer = new IndexWriter(directory, cfg);

         // 4、通过IndexWriter来修改索引

         // a)、创建修改后的文档对象

         Document document = new Document();

         // 文件名称

         Field filenameField = newStringField("filename""updateIndex", Store.YES);

         document.add(filenameField);

         // 修改指定索引为新的索引

         writer.updateDocument(new Term("filename""apache"), document);

         // 5、关闭IndexWriter

         writer.close();

索引的优化


索引优化会消耗大量的cpui/o资源,在使用时得注意,

创建过程


IndexWriter是索引过程的核心组件,通过IndexWriter可以创建新索引、更新索引、删除索引操作。IndexWriter需要通过Directory对索引进行存储操作。

Directory描述了索引的存储位置,底层封装了I/O操作,负责对索引进行存储。它是一个抽象类,它的子类常用的包括FSDirectory(在文件系统存储索引)、RAMDirectory(在内存存储索引)。

创建Document(采集数据的目的是为了索引,在索引前需要将原始内容创建成文档(Document),文档(Document)中包括一个一个的域(Field)。)

// 采集数据

BookDao dao = new BookDaoImpl();

List<Book> list = dao.queryBookList();

// Document对象集合

List<Document> docList = new ArrayList<Document>();

// Document对象

Document doc = null;

for (Book book : list) {

    // 创建Document对象,同时要创建field对象

    doc = new Document();

    // 根据需求创建不同的Field

    Field id = new TextField("id", book.getId().toString(), Store.YES);

    Field name = new TextField("name", book.getName(), Store.YES);

    Field price = new TextField("price", book.getPrice().toString(),Store.YES);

    Field pic = new TextField("pic", book.getPic(), Store.YES);

    Field desc = new TextField("description",   book.getDescription(), Store.YES);

    // 把域(Field)添加到文档(Document)中

    doc.add(id);

    doc.add(name);

    doc.add(price);

    doc.add(pic);

    doc.add(desc);

    docList.add(doc);

}

分词过程

在对Docuemnt中的内容索引之前需要使用分词器进行分词,主要过程就是分词、过虑两步。

  • 分词就是将采集到的文档内容切分成一个一个的词,具体应该说是将DocumentFieldvalue值切分成一个一个的词。
  • 过虑包括去除标点符号、去除停用词(的、是、aanthe等)、大写转小写、词的形还原(复数形式转成单数形参、过去式转成现在式。。。)等。

         什么是停用词?停用词是为节省存储空间和提高搜索效率,搜索引擎在索引页面或处理搜索请求时会自动忽略某些字或词,这些字或词即被称为Stop Words(停用词)。比如语气助词、副词、介词、连接词等,通常自身并无明确的意义,只有将其放入一个完整的句子中才有一定作用,如常见的“的”、“在”、“是”、“啊”等。Lucene作为了一个工具包提供不同国家的分词器,如下图:

注意由于语言不同分析器的切分规则也不同,本例子使用StandardAnalyzer,它可以对用英文进行分词。

如下是org.apache.lucene.analysis.standard.standardAnalyzer的部分源码:

@Override

  protected TokenStreamComponents createComponents(final String fieldName, finalReader reader) {

    finalStandardTokenizer src = newStandardTokenizer(getVersion(), reader);

    src.setMaxTokenLength(maxTokenLength);

    TokenStream tok = newStandardFilter(getVersion(), src);

    tok = newLowerCaseFilter(getVersion(), tok);

    tok = newStopFilter(getVersion(), tok, stopwords);

    returnnew TokenStreamComponents(src, tok) {

      @Override

      protectedvoid setReader(final Reader reader) throws IOException {

        src.setMaxTokenLength(StandardAnalyzer.this.maxTokenLength);

        super.setReader(reader);

      }

    };

  }

Tokenizer是分词器,负责将reader转换为语汇单元即进行分词,Lucene提供了很多的分词器,也可以使用第三方的分词,比如IKAnalyzer一个中文分词器。

tokenFilter是分词过滤器,负责对语汇单元进行过滤,tokenFilter可以是一个过滤器链儿,Lucene提供了很多的分词器过滤器,比如大小写转换、去除停用词等。

如下图是语汇单元的生成过程:

从一个Reader字符流开始,创建一个基于ReaderTokenizer分词器,经过三个TokenFilter生成语汇单元Token

比如下边的文档经过分析器分析如下:

  • 原文档内容:Lucene is a Java full-text search engine. 
  • 分析后得到的语汇单元:lucenejavafulltextsearchengine
  • 同一个域中相同的语汇单元(Token)对应同一个Term(词),它记录了语汇单元的内容及所在域的域名等。
  • 不同的域中拆分出来的相同的单词对应不同的term
  • 相同的域中拆分出来的相同的单词对应相同的term

例如:图书信息里面,图书名称中的java和图书描述中的java对应不同的term

 代码实现

         // 分析文档,对文档中的field域进行分词

         Analyzer analyzer = new StandardAnalyzer();

         // 创建索引

         // a) 创建索引库目录

         Directory directory = FSDirectory.open(new File("E:\\11-index\\0720"));

         // b) 创建IndexWriterConfig对象

         IndexWriterConfig cfg = new IndexWriterConfig(Version.LATEST, analyzer);

         // c) 创建IndexWriter对象

         IndexWriter writer = new IndexWriter(directory, cfg);

         // d) 通过IndexWriter对象添加文档对象(document)

         for (Document document : docList) {

              writer.addDocument(document);

         }

         // f) 关闭IndexWriter

         writer.close();

逻辑结构


3.4.3  索引文件的逻辑结构

  • 文档域:

对非结构化的数据统一格式为document文档格式,一个文档有多个field域,不同的文档其field的个数可以不同,建议相同类型的文档包括相同的field。

本例子一个document对应一条 book表的记录。

  • 索引域:

用于搜索,搜索程序将从索引域中搜索一个一个词,根据词找到对应的文档。

将Document中的Field的内容进行分词,将分好的词创建索引,索引=Field域名:词

  • 倒排索引表

传统方法是先找到文件,如何在文件中找内容,在文件内容中匹配搜索关键字,这种方法是顺序扫描方法,数据量大就搜索慢。

         倒排索引结构是根据内容(词语)找文档,倒排索引结构也叫反向索引结构,包括索引和文档两部分,索引即词汇表,它是在索引中匹配搜索关键字,由于索引内容量有限并且采用固定优化算法搜索速度很快,找到了索引中的词汇,词汇与文档关联,从而最终找到了文档。

索引区对应的是关键分词,文档中区域是存储有关关键分词的数据

|
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值