`
nj_link
  • 浏览: 10235 次
  • 性别: Icon_minigender_1
  • 来自: 厦门
社区版块
存档分类
最新评论

lucene基本架构

    博客分类:
  • java
阅读更多
lucene各个模块用途

建立索引和检索图解

以一个Demo来查看查询代码粗略逻辑
public class TestDemo extends LuceneTestCase {

  public void testDemo() throws IOException, ParseException {
     //创建一个分词器使用Whitespace-lowercasing analyzer,且无停用词.
    Analyzer analyzer = new MockAnalyzer( random);

    //保存索引到内存:
    //Directory directory = newDirectory();
    //会创建2个文件segements.gen(内容为索引的field字段)/segement_N(内容为空)
    // 如果要保存到硬盘,用下面替换:
    Directory directory = FSDirectory. open( new File("D:\\index" ));
    RandomIndexWriter iwriter = new RandomIndexWriter( random, directory, analyzer);
    //maxFieldLength 长度溢出将在这里打印
    iwriter.w.setInfoStream(VERBOSE ? System. out : null);
    //新建文档
    Document doc = new Document();
    //需要索引的值
    String text = "This is the text to be indexed.";
    //建立索引,此时不创建文件放内存,第三个参数设置用来判断是否要分词。
    doc.add(newField("fieldname" , text, Field.Store.YES, Field.Index.ANALYZED));
    //创建2个文件.fdt.ftx但是没有填充值
    iwriter.addDocument(doc);
    //这里默认commit了,填充了值,合并段,合并文档等,还创建了其他各种文件
    iwriter.close();
   
    // 查询索引:
    IndexReader ireader = IndexReader.open(directory); // read-only=true
    IndexSearcher isearcher = new IndexSearcher(ireader);
    //创建个默认查询,文字:"text":
    QueryParser parser = new QueryParser( TEST_VERSION_CURRENT, "fieldname", analyzer);
    Query query = parser.parse("text");
    TopDocs hits = isearcher.search(query, null, 1);

    // 循环结果集:
    for (int i = 0; i < hits. scoreDocs. length; i++) {
      Document hitDoc = isearcher.doc(hits. scoreDocs[i]. doc);
      assertEquals("This is the text to be indexed." , hitDoc.get("fieldname"));
    }

    // 测试短语
    query = parser.parse("\"to be\"");
    assertEquals (1, isearcher.search(query, null, 1).totalHits);

    //记得手动关闭
    isearcher.close();
    ireader.close();
    directory.close();
  }
}

Document.add()方法流程

这个方法主要功能是将field字段和值保存到缓存中去,等待close()方法调用时写入文件。其中为了增加效率启用了多线程创建索引分词。分词组件可以自己实现只要继承Analyzer类。在分词组件里面重载incrementToken(不大记得好像是)或者自己实现一个类继承Tocken,在类里面重载incrementToken方法。这样,如果索引字段的定义了需要分词的话,就会调用你重载的这个方法,以此实现自定义分词效果。
  public TokenStream reusableTokenStream(String fieldName, Reader reader)
      throws IOException;

看了4.9+的代码,这个方法以及被定义为final。作者开发了另一个方法来提供用户重载,实现一样效果。
 protected Analyzer.TokenStreamComponents createComponents(String fieldName, Reader reader);

下面贴一个程序运行的关键代码,以及基于4.7.0实现的一个Analyzer.
//保证多个进程同时读取Directory不出问题。对一个lockFactory的引用来锁定文件
public abstract class Directory implements Closeable {
     protected LockFactory lockFactory;
}
//锁定文件,因为采用多个线程同时进行分词,同时只能有一个线程对缓存进行读写
public abstract class LockFactory {
     public abstract Lock makeLock(String lockName);
     abstract public void clearLock(String lockName) throws IOException;
}
//保存索引文件的原文档
public final class Document implements java.io.Serializable {
  List<Fieldable> fields = new ArrayList<Fieldable>();
}
//分词组件,有2个重载方法。功能:1、分词。2、停词。3、去掉标点。可以自己实现分词
public final class MockAnalyzer extends Analyzer {
  private final int pattern;
  private final boolean lowerCase;
  private final CharArraySet filter;
  private final boolean enablePositionIncrements;
  private int positionIncrementGap;
  private final Random random;
  private Map<String,Integer > previousMappings = new HashMap<String,Integer>();
  private boolean enableChecks = true;
  private int maxTokenLength = MockTokenizer.DEFAULT_MAX_TOKEN_LENGTH ;

  maybePayload() {
    //影响词的评分
    token.setPayload(new PayLoad((Field)_id.getByte()));
  }

  //这个方法返回一个TokenStreamComponents,设置reader,filters,token。(lucene4.10这个方法为final不可继承)
  public TokenStream reusableTokenStream(String fieldName, Reader reader)
      throws IOException {
     @SuppressWarnings("unchecked" ) Map<String,SavedStreams> map = (Map) g     etPreviousTokenStream();
    if (map == null) {
      map = new HashMap<String,SavedStreams>();
      setPreviousTokenStream(map);
    }
   
    SavedStreams saved = map.get(fieldName);
    if (saved == null) {
      saved = new SavedStreams();
      saved.tokenizer = new MockTokenizer(reader, pattern, lowerCase, maxTokenLength);
      saved.tokenizer.setEnableChecks( enableChecks);
      StopFilter filt = new StopFilter(LuceneTestCase.TEST_VERSION_CURRENT ,                saved.tokenizer , filter);
      filt.setEnablePositionIncrements(enablePositionIncrements );
      //这里用的是责任链模式。类似saved.filter=A,A.filter=B,B..filter=c以此类推
      saved.filter = filt;
      //是否使用跳跃表,不设置的话,如果索引一旦增长(根据分词判断是否使用同一个字典链表)过长,lucene会自动使用。
      saved.filter = maybePayload(saved. filter, fieldName);
      //关键是这一行,将filter放入map,可以放入多个,类型为TokenFilter
      map.put(fieldName, saved);
      return saved. filter;
    } else {
      saved.tokenizer.reset (reader);
      return saved. filter;
    }
  }
}
//filter超类
public class Token {
    //默认对是否进行使用跳跃表的实现
    private Payload payload;
}

writer.close()方法的流程(用画图工具画的,超级烂。下次引以为戒)

关键的一部分代码:
//创建、写入文件segments
public class IndexWriter implements Closeable, TwoPhaseCommit {
    //这里创建segments.gen,segments_N文件以及保存数据
    private synchronized final void finishCommit() throws CorruptIndexException, IOException {
        pendingCommit .finishCommit(directory);
    }
     
    //入口
    private void closeInternal(boolean waitForMerges) throws CorruptIndexException, IOException {
        //创建各种文件,(除segments*,.fdt.fdx),先组装数据,后合并数据,写入文件操作
        flush(waitForMerges, true);
        //会调用到finishCommit()
        commitInternal(null);      
    } 
}

英文单词大小写处理
lucene用他自带的standardAnalyzer在建立索引的时候是区分大小写的。在查询query的时候会通通转成小写,导致查询不到。那么可以复制一份源代码,放到本地改一下。调用本地就可以
  protected TokenStreamComponents createComponents(final String fieldName, final Reader reader) {
    final StandardTokenizer src = new StandardTokenizer(matchVersion, reader);
    src.setMaxTokenLength(maxTokenLength);
    src.setReplaceInvalidAcronym(replaceInvalidAcronym);
    TokenStream tok = new StandardFilter(matchVersion, src);
    //注释掉这一句
    //tok = new LowerCaseFilter(matchVersion, tok);
    tok = new StopFilter(matchVersion, tok, stopwords);
    return new TokenStreamComponents(src, tok) {
      @Override
      protected boolean reset(final Reader reader) throws IOException {
        src.setMaxTokenLength(StandardAnalyzer.this.maxTokenLength);
        return super.reset(reader);
      }
    };

参考:
因为lucene虽然版本升级,方法上有很多改变,我感觉用户体验明显好多了。但是目前他整体的架构没看得大改变。所以以前的一些书籍还是可以看得。记录一下文档地址,这是一本很好的书:http://www.open-open.com/doc/view/f92fa668d8b84626abd20a05b6eb014e
  • 大小: 175.1 KB
  • 大小: 4.2 KB
  • 大小: 241.8 KB
  • 大小: 13.4 KB
  • 大小: 14.9 KB
  • 大小: 88 KB
分享到:
评论

相关推荐

    lucene基本包

    Lucene一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎

    lucene in action_中文版(lucene实战)

    它通过浅显的语言、大量的图注、丰富的代码示例,以及清晰的结构为读者呈现出作为优秀开源项目的Lucene 所体现的强大功能。全书共10章,分为两大部分。第1部分Lucene的核心,着重于Lucene的核心API介绍,并按照把...

    LuceneInAction 第2版 中文版 pdf

    本书深入浅出地介绍了lucene 一个开源的使用java语言编写的全文搜索引擎开发包 它通过浅显的语言 大量的图注 丰富的代码示例 以及清晰的结构为读者呈现出作为优秀开源项目的lucene所体现的强大功能 全书共10章 分为...

    Lucene 3.0 原理与代码分析PDF

    Lucene学习总结之一:全文检索的基本原理 Lucene学习总结之二:Lucene的总体架构 Lucene学习总结之三:Lucene的索引文件格式(1) Lucene学习总结之三:Lucene的索引文件格式(2) Lucene学习总结之三:Lucene的...

    基于Lucene的实时全文检索系统(含论文)

    本文主要是研究了全文检索技术的基本原理以及Lucene的架构和工作原理,并介绍了基于Lucene的实时全文检索引擎的设计实现过程。并提供了一个基于Web的简单实现。最后通过实验的方式,对实现的实时全文检索引擎的性能...

    Lucene.net 系列教程

    Lucene.net 系列教程,讲解Lucene.net的基本架构

    Lucene 3.0 原理与代码分析

    本系列文章将详细描述几乎最新版本的Lucene的基本原理和代码分析。 其中总体架构和索引文件格式是Lucene 2.9的,索引过程分析是Lucene 3.0的。 鉴于索引文件格式没有太大变化,因而原文没有更新,原理和架构的文章中...

    Lucene in Action

    它通过浅显的语言、大量的图注、丰富的代码示例,以及清晰的结构为读者呈现出作为优秀开源项目的Lucene所体现的强大功能。全书共10章,分为两大部分。第1部分Lucene的核心,着重于Lucene的核心API介绍,并按照把...

    Lucene 3.0 原理与代码分析完整版

    1.1 Lucene学习总结之一:全文检索的基本原理 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.2 Lucene学习总结之二:Lucene的总体架构 . . . . . . . . . . . . ...

    Lucene介绍的PPT

    Lucene API的介绍,适合入门的人学习.包括全文索引文件的基本结构.

    Lucene研究,Lucene 读书笔记

    一、 全文检索的基本概念 (1)、数据总体分为两种:结构化数据和非结构化数据。 结构化数据:指具有固定格式或有限长度的数据,如数据库,元数据等。 非结构化数据:指不定长或无固定格式的数据,如邮件,word文档等...

    搜索链接java(结合lucene)版的公交搜索系统

    该系统实现了urban公交线路搜索的基本功能,页面简洁且交互良好,搜索速度较快,代码结构清晰易理解。但是也存在一定缺点,如站点信息较少,无实时信息如可达线路,安全和稳定性也较差,不适合直接商业应用。 总之,该java...

    java(结合lucene)版的公交搜索系统的实现.rar

    整个系统的架构可以分为前端和后端两部分,前端负责接收用户输入并向后端发送搜索请求,后端则负责处理搜索请求,从 Lucene 索引中检索相关的公交信息,并返回给前端展示。同时,后端还需要实现定时任务来更新 ...

    Lucene中文分词组件 JE-Analysis 1.4.0

    分词效率: 第一次分词需要1-2秒(读取词典),之后速度基本与Lucene自带分词持平 运行环境: Lucene 1.9+ 内存消耗: 30M+ 1.4.0 —— 2006-08-21 增加词典的动态扩展能力 1.3.3 —— 2006-07...

    jpa-lucene-spring-demo:使用JPA,Lucene,Spring,DBUnit和JMockit的演示项目-持久并搜索简单的Book数据

    jpa-lucene-spring-demo Javalobby上的完整文章: : 也在博客上: : 使用JPA,Lucene,Spring,DBUnit和JMockit的演示项目-持久并搜索... 该示例很简单,但是说明了如何连接基础结构以集成Lucene和JPA的基本概念。

    基于Lucene全文检索引擎的应用研究

    Lucene是一个强大的全文索引引擎工具包, 它的全文检索技术是信息检索领域广泛使用的基本技术, 具有访问索引时间快、多用户访问、跨平台使用的特点。介绍了一个高性能的全文检索引擎——Lucene开源系统,详细分析了...

    搜索引擎----面试笔记2

    面试官心理分析 在搜索这块,lucene 是最流行的搜索库。几年前业内一般都问,你了解 lucene 吗?你知道倒排索引的原理吗?现在早已经 out 了,因为现在很多项目都是...就看看你对分布式搜索引擎架构的一个基本理解。

    大型分布式网站架构与实践

     垂直化的搜索引擎在分布式系统中的使用,包括搜索引擎的基本原理、Lucene详细的使用介绍,以及基于Lucene的开源搜索引擎工具Solr的使用。  2.1 分布式缓存 60  2.1.1 memcache简介及安装 60  2.1.2 memcache ...

    ELK入门到精通

    后文的四种基本架构中将逐一介绍应用到的其它套件。 Elasticsearch是实时全文搜索和分析引擎,提供搜集、分析、存储数据三大功能;是一套开放REST和JAVA API等结构提供高效搜索功能,可扩展的分布式系统。它构建于...

    Solr原理以及基本应用.pptx

    关于solr的一些基础入门,基于solr6.5,了解之后可以基本上架构出属于自己的搜索引擎

Global site tag (gtag.js) - Google Analytics