Lucene(一)
- 格式:ppt
- 大小:532.50 KB
- 文档页数:44


Lucene⼊门+实现Lucene简介详情见:()lucene实现原理其实⽹上很多资料表明了,lucene底层实现原理就是倒排索引(invertedindex)。
那么究竟什么是倒排索引呢?经过Lucene分词之后,它会维护⼀个类似于“词条--⽂档ID”的对应关系,当我们进⾏搜索某个词条的时候,就会得到相应的⽂档ID。
不同于传统的顺排索引根据⼀个词,知道有哪⼏篇⽂章有这个词。
图解:Lucene在搜索前⾃⾏⽣成倒排索引,相⽐数据库中like的模糊搜索效率更⾼!Lucene 核⼼API索引过程中的核⼼类1. Document⽂档:他是承载数据的实体(他可以集合信息域Field),是⼀个抽象的概念,⼀条记录经过索引之后,就是以⼀个Document的形式存储在索引⽂件中的。
2. Field:Field 索引中的每⼀个Document对象都包含⼀个或者多个不同的域(Field),域是由域名(name)和域值(value)对组成,每⼀个域都包含⼀段相应的数据信息。
3. IndexWriter:索引过程的核⼼组件。
这个类⽤于创建⼀个新的索引并且把⽂档加到已有的索引中去,也就是写⼊操作。
4. Directroy:是索引的存放位置,是个抽象类。
具体的⼦类提供特定的存储索引的地址。
(FSDirectory 将索引存放在指定的磁盘中,RAMDirectory ·将索引存放在内存中。
)5. Analyzer:分词器,在⽂本被索引之前,需要经过分词器处理,他负责从将被索引的⽂档中提取词汇单元,并剔除剩下的⽆⽤信息(停⽌词汇),分词器⼗分关键,因为不同的分词器,解析相同的⽂档结果会有很⼤的不同。
Analyzer是⼀个抽象类,是所有分词器的基类。
搜索过程中的核⼼类1. IndexSearcher :IndexSearcher 调⽤它的search⽅法,⽤于搜索IndexWriter 所创建的索引。
2. Term :Term 使⽤于搜索的⼀个基本单元。
另外,如果是在选择全文引擎,现在也许是试试Sphinx的时候了:相比Lucene速度更快,有中文分词的支持,而且内置了对简单的分布式检索的支持;基于Java的全文索引/检索引擎——LuceneLucene不是一个完整的全文索引应用,而是是一个用Java写的全文索引引擎工具包,它可以方便的嵌入到各种应用中实现针对应用的全文索引/检索功能。
Lucene的作者:Lucene的贡献者Doug Cutting是一位资深全文索引/检索专家,曾经是V-Twin搜索引擎(Apple的Copland操作系统的成就之一)的主要开发者,后在Excite担任高级系统架构设计师,目前从事于一些INTERNET底层架构的研究。
他贡献出的Lucene的目标是为各种中小型应用程序加入全文检索功能。
Lucene的发展历程:早先发布在作者自己的,后来发布在SourceForge,2001年年底成为APACHE基金会jakarta的一个子项目:/lucene/已经有很多Java项目都使用了Lucene作为其后台的全文索引引擎,比较著名的有:对于中文用户来说,最关心的问题是其是否支持中文的全文检索。
但通过后面对于Lucene 的结构的介绍,你会了解到由于Lucene良好架构设计,对中文的支持只需对其语言词法分析接口进行扩展就能实现对中文检索的支持。
全文检索≠ like "%keyword%"通常比较厚的书籍后面常常附关键词索引表(比如:北京:12, 34页,上海:3,77页……),它能够帮助读者比较快地找到相关内容的页码。
而数据库索引能够大大提高查询的速度原理也是一样,想像一下通过书后面的索引查找的速度要比一页一页地翻内容高多少倍……而索引之所以效率高,另外一个原因是它是排好序的。
对于检索系统来说核心是一个排序问题。
由于数据库索引不是为全文索引设计的,因此,使用like "%keyword%"时,数据库索引是不起作用的,在使用like查询时,搜索过程又变成类似于一页页翻书的遍历过程了,所以对于含有模糊查询的数据库服务来说,LIKE对性能的危害是极大的。
一步一步跟我学习lucene(1...自定义排序说明我们在做lucene搜索的时候,可能会需要排序功能,虽然lucene 内置了多种类型的排序,但是如果在需要先进行某些值的运算然后在排序的时候就有点显得无能为力了;要做自定义查询,我们就要研究lucene已经实现的排序功能,lucene的所有排序都是要继承FieldComparator,然后重写内部实现,这里以IntComparator为例子来查看其实现;IntComparator相关实现其类的声明为public static class IntComparator extends NumericComparator<Integer>,这里说明IntComparator接收的是Integer类型的参数,即只处理IntField的排序;IntComparator声明的参数为:[java] view plain copy1.private final int[] values;2.private int bottom; // Value of bottom of queue3.private int topValue;查看copy方法可知•values随着类初始化而初始化其长度•values用于存储NumericDocValues中读取到的内容具体实现如下:values的初始化[java] view plain copy1./**2.* Creates a new comparator based on {@link Integer#co mpare} for {@code numHits}.3.* When a document has no value for the field, {@code mi ssingValue} is substituted.4.*/5.public IntComparator(int numHits, String field, Integer mi ssingValue) {6.super(field, missingValue);7.values = new int[numHits];8.}values值填充(此为IntComparator的处理方式)[java] view plain copy1.@Override2.public void copy(int slot, int doc) {3.int v2 = (int) currentReaderValues.get(doc);4.// Test for v2 == 0 to save Bits.get method call for5.// the common case (doc has value and value is non-zero):6.if (docsWithField != null && v2 == 0 && !docsWithField. get(doc)) {7.v2 = missingValue;8.}9.10.values[slot] = v2;11.}这些实现都是类似的,我们的应用实现自定义排序的时候需要做的是对binaryDocValues或NumericDocValues的值进行计算,然后实现FieldComparator内部方法,对应IntComparator就是如上的值copy操作;然后我们需要实现compareTop、compareBottom和compare,IntComparator的实现为:[java] view plain copy1.@Override2.public int compare(int slot1, int slot2) {3.return pare(values[slot1], values[slot2]);4.}5.6.@Override7.public int compareBottom(int doc) {8.int v2 = (int) currentReaderValues.get(doc);9.// Test for v2 == 0 to save Bits.get method call for10.// the common case (doc has value and value is non-zero):11.if (docsWithField != null && v2 == 0 && !docsWithFi eld.get(doc)) {12.v2 = missingValue;13.}14.15.return pare(bottom, v2);16.}[java] view plain copy1.@Override2.public int compareTop(int doc) {3.int docValue = (int) currentReaderValues.get(doc);4.// Test for docValue == 0 to save Bits.get method call for5.// the common case (doc has value and value is non-zero):6.if (docsWithField != null && docValue == 0 && !docsWit hField.get(doc)) {7.docValue = missingValue;8.}9.return pare(topValue, docValue);10.}实现自己的FieldComparator要实现FieldComparator,需要对接收参数进行处理,定义处理值的集合,同时定义BinaryDocValues和接收的参数等,这里我写了一个通用的比较器,代码如下:[java] view plain copy1.package com.lucene.search;2.3.import java.io.IOException;4.5.import org.apache.lucene.index.BinaryDocValues;6.import org.apache.lucene.index.DocValues;7.import org.apache.lucene.index.LeafReaderContext;8.import org.apache.lucene.search.SimpleFieldComparator;9.10.import com.lucene.util.ObjectUtil;11.12./**自定义comparator13.* @author lenovo14.*15.*/16.public class SelfDefineComparator extends SimpleFie ldComparator<String> {17.private Object[] values;//定义的Object[],同IntComparator18.private Object bottom;19.private Object top;20.private String field;21.private BinaryDocValues binaryDocValues;//接收的BinaryDocValues,同IntComparator中的NumericDocValues22.private ObjectUtil objectUtil;//这里为了便于拓展用接口代替抽象类23.private Object[] params;//接收的参数24.25.public SelfDefineComparator(String field, int numHits, Object[] params,ObjectUtil objectUtil) {26.values = new Object[numHits];27.this.objectUtil = objectUtil;28.this.field = field;29.this.params = params;30.}31.32.@Override33.public void setBottom(int slot) {34.this.bottom = values[slot];35.}36.37.@Override38.public int compareBottom(int doc) throws IOExcepti on {39.Object distance = getValues(doc);40.return (bottom.toString()).compareTo(distance.toStrin g());41.}42.43.@Override44.public int compareTop(int doc) throws IOException {45.Object distance = getValues(doc);46.return pareTo(top,distance);47.}48.49.@Override50.public void copy(int slot, int doc) throws IOException {51.values[slot] = getValues(doc);52.}53.54./**��ȡdocID��Ӧ��value55.* @param doc56.* @return57.*/58.private Object getValues(int doc) {59.Object instance = objectUtil.getValues(doc,params,bin aryDocValues) ;60.return instance;61.}62.63.@Override64.protected void doSetNextReader(LeafReaderContext context)65.throws IOException {66.binaryDocValues = DocValues.getBinary(context.reade r(), field);//context.reader().getBinaryDocValues(field);67.}68.69.@Override70.public int compare(int slot1, int slot2) {71.return pareTo(values[slot1],values[slot2]);72.}73.@Override74.public void setTopValue(String value) {75.this.top = value;76.}77.78.@Override79.public String value(int slot) {80.return values[slot].toString();81.}82.83.}其中ObjectUtil是一个接口,定义了值处理的过程,最终是要服务于comparator的compare方法的,同时对comparator的内部compare方法进行了定义ObjectUtil接口定义如下:[java] view plain copy1.package com.lucene.util;2.3.import org.apache.lucene.index.BinaryDocValues;4.5.public interface ObjectUtil {6.7./**自定义的获取处理值的方法8.* @param doc9.* @param params10.* @param binaryDocValues11.* @return12.*/13.public abstract Object getValues(int doc, Object[] par ams, BinaryDocValues binaryDocValues) ;14.15./**compare比较器实现16.* @param object17.* @param object218.* @return19.*/20.public abstract int compareTo(Object object, Object object2);21.22.}我们不仅要提供比较器和comparator,同时还要提供接收用户输入的FiledComparatorSource[java] view plain copy1.package com.lucene.search;2.3.import java.io.IOException;4.5.import org.apache.lucene.search.FieldComparator;6.import org.apache.lucene.search.FieldComparatorSource;7.8.import com.lucene.util.ObjectUtil;9.10./**comparator用于接收用户原始输入,继承自FieldComparatorSource实现了自定义comparator的构建11.* @author lenovo12.*13.*/14.public class SelfDefineComparatorSource extends Fie ldComparatorSource {15.private Object[] params;//接收的参数16.private ObjectUtil objectUtil;//这里为了便于拓展用接口代替抽象类17.18.public Object[] getParams() {19.return params;20.}21.22.public void setParams(Object[] params) {23.this.params = params;24.}25.26.public ObjectUtil getObjectUtil() {27.return objectUtil;28.}29.30.public void setObjectUtil(ObjectUtil objectUtil) {31.this.objectUtil = objectUtil;32.}33.34.public SelfDefineComparatorSource(Object[] params, ObjectUtil objectUtil) {35.super();36.this.params = params;37.this.objectUtil = objectUtil;38.}39.40.@Override41.public FieldComparator<?> newComparator(String fie ldname, int numHits,42.int sortPos, boolean reversed) throws IOException {43.//实际比较由SelfDefineComparator实现44.return new SelfDefineComparator(fieldname, numHit s, params, objectUtil);45.}46.}相关测试程序,这里我们模拟一个StringComparator,对String 值进行排序[java] view plain copy1.package com.lucene.search;2.3.import org.apache.lucene.analysis.Analyzer;4.import org.apache.lucene.analysis.standard.StandardAnal yzer;5.import org.apache.lucene.document.BinaryDocValuesFiel d;6.import org.apache.lucene.document.Document;7.import org.apache.lucene.document.Field;8.import org.apache.lucene.document.StringField;9.import org.apache.lucene.index.DirectoryReader;10.import org.apache.lucene.index.IndexReader;11.import org.apache.lucene.index.IndexWriter;12.import org.apache.lucene.index.IndexWriterConfig;13.import org.apache.lucene.index.IndexWriterConfig.Op enMode;14.import org.apache.lucene.index.Term;15.import org.apache.lucene.search.IndexSearcher;16.import org.apache.lucene.search.MatchAllDocsQuery;17.import org.apache.lucene.search.Query;18.import org.apache.lucene.search.ScoreDoc;19.import org.apache.lucene.search.Sort;20.import org.apache.lucene.search.SortField;21.import org.apache.lucene.search.TermQuery;22.import org.apache.lucene.search.TopDocs;23.import org.apache.lucene.search.TopFieldDocs;24.import org.apache.lucene.store.RAMDirectory;25.import org.apache.lucene.util.BytesRef;26.27.import com.lucene.util.CustomerUtil;28.import com.lucene.util.ObjectUtil;29.import com.lucene.util.StringComparaUtil;30.31./**32.*33.* @author 吴莹桂34.*35.*/36.public class SortTest {37.public static void main(String[] args) throws Exceptio n {38.RAMDirectory directory = new RAMDirectory();39.Analyzer analyzer = new StandardAnalyzer();40.IndexWriterConfig indexWriterConfig = new IndexWri terConfig(analyzer);41.indexWriterConfig.setOpenMode(OpenMode.CREATE_ OR_APPEND);42.IndexWriter indexWriter = new IndexWriter(directory,indexWriterConfig);43.addDocument(indexWriter, "B");44.addDocument(indexWriter, "D");45.addDocument(indexWriter, "A");46.addDocument(indexWriter, "E");mit();48.indexWriter.close();49.IndexReader reader = DirectoryReader.open(directory) ;50.IndexSearcher searcher = new IndexSearcher(reader);51.Query query = new MatchAllDocsQuery();52.ObjectUtil util = new StringComparaUtil();53.Sort sort = new Sort(new SortField("name",new SelfD efineComparatorSource(new Object[]{},util),true));54.TopDocs topDocs = searcher.search(query, Integer.MA X_VALUE, sort);55.ScoreDoc[] docs = topDocs.scoreDocs;56.for(ScoreDoc doc : docs){57.Document document = searcher.doc(doc.doc);58.System.out.println(document.get("name"));59.}60.}61.62.private static void addDocument(IndexWriter writer,S tring name) throws Exception{63.Document document = new Document();64.document.add(new StringField("name",name,Field.Sto re.YES));65.document.add(new BinaryDocValuesField("name", new BytesRef(name.getBytes())));66.writer.addDocument(document);67.}68.}其对应的ObjectUtil实现如下:[java] view plain copy1.package com.lucene.util;2.3.import org.apache.lucene.index.BinaryDocValues;4.import org.apache.lucene.util.BytesRef;5.6.public class StringComparaUtil implements ObjectUtil {7.8.@Override9.public Object getValues(int doc, Object[] params,10.BinaryDocValues binaryDocValues) {11.BytesRef bytesRef = binaryDocValues.get(doc);12.String value = bytesRef.utf8T oString();13.return value;14.}15.16.@Override17.public int compareTo(Object object, Object object2) {18.// TODO Auto-generated method stub19.return object.toString().compareTo(object2.toString());20.}21.22.}。