Lucene创建,读取,优化 总结(一)

栏目: 编程工具 · 发布时间: 6年前

内容简介:Lucene创建,读取,优化 总结(一)

The goal of Apache Lucene and Solr is to provide world class search capabilities

上面这句话是apache在官网上对Lucene的介绍。本文对Lucene做一个入门级的介绍,其实每一部分都可以单独写一篇文章。

当数据量越来越大的时候,大数据量对于数据库还是有一定压力,一般采用分表,分表后读取数据也可能会比较慢,尤其是有很多搜索条件。如果数据量不大,并且读取写入频繁,可以采用Radis,实现master-slave(主从)同步。如果千万级别的数据量且对数据的读取速度有一定要求,就需要建索引,Lucene是不错的选择。

Lucene通过对存储内容建立索引,提高查询效率,索引文件存储在硬盘/内存上,索引类似字典上面的a-b-c-d顺序,a-b-c-d对应Lucene中的Field。

Lucene常用类介绍

  • (1)IndexWriter :

An IndexWriter creates and maintains an index. 用来创建并管理索引文件。该类负责创建新索引或者打开已有索引,以及向索引中添加、删除或更新索引文档的信息,但不能用于读取或搜索索引。IndexWriter需要开辟一定空间来存储索引,该功能可以由Directory完成。IndexWriter有以下几种创建模式:IndexWriterConfig.OpenMode

APPENDOpens an existing index.

CREATECreates a new index or overwrites an existing one.

CREATE_OR_APPENDCreates a new index if one does not exist, otherwise it opens the index and documents will be appended. 另外有几点需要注意: 1:如果在创建索引文件过程中出现OutOfMemoryError,随之调用commit()会出现IllegalStateException,Lucene内部会记录当前出现异常的位置,此时必须调用close()方法处理异常,close()方法内部会回滚状态到上一次提交的位置。当然也可以手动调用rollback()。所以在try,catch后一定加上finally,并在finally中调用close()方法。2:Lucene方法都是线程安全的,内部涉及写入文件都是加锁的,可以多线程使用,所以在使用时不需要再加锁,尤其是IndexWriter实例不要加锁,不然有可能造成死锁。

  • (2)Directory :A Directory is a flat list of files. Files may be written once, when they are created. Once a file is created it may only be opened for read, or deleted. Random access is permitted both when reading and writing. 索引存放的位置,它是一个抽象类,它的子类负责具体制定索引的存储路径。支持读共享,写独占的方式来访问索引目录。lucene提供了两种索引存放的位置,一种是磁盘,一种是内存。一般情况将索引放在磁盘上;相应地lucene提供了FSDirectory(硬盘)和RAMDirectory(内存)两个类。Java的io操作Api都是通过这个类来操作。

  • (3)Analyzer TokenStream Token:这三个都是analysis包下面的类,这里放在一起说了。Package org.apache.lucene.analysisAPI and code to convert text into indexable/searchable tokens. Covers Analyzer and related classes.Parsing? Tokenization? Analysis!Lucene, an indexing and search library, accepts only plain text input.所以analysis包就是用来处理文本的。

Analyzer :An Analyzer builds TokenStreams, which analyze text. It thus represents a policy for extracting index terms from text. 分析器或分词器,主要用于分析搜索引擎遇到的各种文本,Analyzer的工作是一个复杂的过程:把一个字符串按某种规则划分成一个个词语,并去除其中的无效词语,去掉有利于缩小索引文件、提高效率、提高命中率。分词的规则千变万化,在analysis包中含有多种分词器,当然也可以自己定义分词器。Lucene文档给出了以下几种实现好的分词器:

  • Common: Analyzers for indexing content in different languages and domains. 这里面有很多,常用的有:SimpleAnalyzer、CJKAnalyzer、IKAnalyzer、StandardAnalyzer。
  • ICU: Exposes functionality from ICU to Apache Lucene.
  • Kuromoji: Morphological analyzer for Japanese text.
  • Morfologik: Dictionary-driven lemmatization for the Polish language.
  • Phonetic: Analysis for indexing phonetic signatures (for sounds-alike search).
  • Smart Chinese: Analyzer for Simplified Chinese, which indexes words.
  • Stempel: Algorithmic Stemmer for the Polish Language.
  • UIMA: Analysis integration with Apache UIMA.

TokenStream 是用来代替Token的Api:从Lucene2.9以后不再推荐使用Token;

TokenStream 介绍:A TokenStream enumerates the sequence of tokens, either from Field Document or from query text. 分词器做好处理之后得到的一个流,这个流中存储了分词的各种信息.可以通过TokenStream有效的获取到分词单元,从而获取各个分词的信息。

//第一个参数只是标识性没有实际作用             TokenStream stream = analyzer.tokenStream("", new StringReader(str));             //获取词与词之间的位置增量             PositionIncrementAttribute postiona = stream.addAttribute(PositionIncrementAttribute.class);             //获取各个单词之间的偏移量             OffsetAttribute offseta = stream.addAttribute(OffsetAttribute.class);             //获取每个单词信息             CharTermAttribute chara = stream.addAttribute(CharTermAttribute.class);             //获取当前分词的类型             TypeAttribute typea = stream.addAttribute(TypeAttribute.class);             while(stream.incrementToken()){                 System.out.print("位置增量" +postiona.getPositionIncrement()+":\t");                 System.out.println(chara+"\t[" + offseta.startOffset()+" - " + offseta.endOffset() + "]\t<" + typea +">");             }             System.out.println();
  • (4) Document : The logical representation of a Document for indexing and searching.文档 Document相当于一个要进行索引的单元,可以是文本文件、字符串或者数据库表的一条记录等等,一条记录经过索引之后,就是以一个Document的形式存储在索引文件,索引的文件都必须转化为Document对象才能进行索引。这个没什么可说的,下面会有一段代码简单描述索引创建过程看一下就知道了。
  • (5) Field :一个Document可以包含多个信息域,比如一篇文章可以包含“标题”、“正文”等信息域,这些信息域就是通过Field在Document中存储的。一个Field包含内容,是否存储,是否分词等,这可由构造函数看出:

    xxmcField = new Field("xxmc", "", Field.Store.YES, Field.Index.ANALYZED_NO_NORMS); xxmc.setValue("laotie");

    其中"xxmc"是键值中的键名,"laotie"是值,Field.Store.YES代表存储内容,如果使用索引查询后需要展示其内容,那么选择存储即可,如果不需要展示只是用来索引,那么Field.Store.NO,分词则表示是否用分词器对内容分词,便于搜索。

  • (6) IndexReader :IndexReader is an abstract class, providing an interface for accessing an index. 打开一个Directory读取索引类。同样值得注意的是,Lucene在内部已经保证了线程安全,不需外部对IndexReader的实例加锁,不然可能造成死锁。

  • (7) IndexSearcher:To perform a search, applications usually call IndexSearcher.search(Query,int) or IndexSearcher.search(Query,Filter,int). 是lucene中最基本的检索工具,所有的检索都会用到IndexSearcher工具。创建索引最终就是为了搜索,这部分涉及比较复杂的就是打分,也就是一个索引的分数即其重要程度。而其分值可以直接影响搜索结果的排名。关于评分机制可以参考。

  • (8)Query查询,抽象类,必须通过一系列子类来表述检索的具体需求,lucene中支持模糊查询,语义查询,短语查询,组合查询等等,如有 TermQuery,BooleanQuery,RangeQuery,WildcardQuery等一些类。创建索引的典型方式,重用Document与Field:

    Document doc = new Document(); Field field1 = new TextField("field1", field1Value, Field.Store.YES); doc.add(field1); Field field2 = new StringField("field2", field2Value,Field.Store.YES); doc.add(field2); while ((line = br.readLine()) != null) {   field1.setStringValue("field1Value");   field2.setStringValue("field2Value");    writer.addDocument(doc); }
  • 重点介绍一下这几种Query方式

    TermQuery

这是一种最简单的查询,类似键值对,使用键和值去索引里查询包含对应键值的数据。可以用来构成BooleanQuery.

BooleanQuery

A Query that matches documents matching boolean combinations of other queries其实这个就是一种组合查询,其中组合方式可以选择MUST, NOT_MUST, SHOULD。其中SHOULD其实只是按打分影响排名,具体组合参考:

  • 1.MUST和MUST:取得连个查询子句的交集。
  • 2.MUST和MUST_NOT:表示查询结果中不能包含MUST_NOT所对应得查询子句的检索结果。
  • 3.SHOULD与MUST_NOT:连用时,功能同MUST和MUST_NOT。
  • 4.SHOULD与MUST连用时,结果为MUST子句的检索结果,但是SHOULD可影响排序。
  • 5.SHOULD与SHOULD:表示“或”关系,最终检索结果为所有检索子句的并集。
  • 6.MUST_NOT和MUST_NOT:无意义,检索无结果。

RangeQuery:NumericRangeQuery和TermRangeQuery两种

范围查询,一般NumericRangeQuery用的比较多,用来查询数字范围,比如价格,人数等等。TermRangeQuery也是范围查询但最终转为AscII码,文档上写的就是最终比较byte,Byte.compareTo(byte). 所以不如NumericRangeQuery查询使用的多。

WildcardQuery

这个是通配符查询,使用文档里的通配符查询每个item中的内容,比如"use*"可以查到"useful"、"user"。注意:这个查询比较慢,因为要查询每个item,,为了避免极慢的查询速度,请不要使用以星号开头的通配符进行查询。另外,WildcardQuery对于用户输入的查询关键字是大小写敏感的,请不要使用大写形式,因为索引中的Term都是小写形式的。

下一篇介绍:Lucene 建立及读取的例子,优化的几个方面


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

SRE

SRE

贝特西 拜尔 (Betsy Beyer)、等 / 孙宇聪 / 电子工业出版社 / 2016-10-1 / CNY 108.00

大型软件系统生命周期的绝大部分都处于“使用”阶段,而非“设计”或“实现”阶段。那么为什么我们却总是认为软件工程应该首要关注设计和实现呢?在《SRE:Google运维解密》中,Google SRE的关键成员解释了他们是如何对软件进行生命周期的整体性关注的,以及为什么这样做能够帮助Google成功地构建、部署、监控和运维世界上现存最大的软件系统。通过阅读《SRE:Google运维解密》,读者可以学习到......一起来看看 《SRE》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具