Lucene源码(一):分词器的底层原理

news/2024/7/19 20:45:43 标签: 全文检索, lucene, 搜索, java, 源码

文章目录

  • 官方Demo
    • Query
    • Term
    • StandardAnalyzer
  • 源码分析
    • QueryBuilder.createFieldQuery
    • StandardTokenizer
    • StandardTokenizerImpl

官方Demo

我们先看官方提供的demo代码,从使用demo运行一遍,看看分词之后的结果,然后再对源码进行研究。分词的核心代码其实就是这几句:

java">Analyzer analyzer = new StandardAnalyzer();
QueryParser parser = new QueryParser(field, analyzer);
Query query = parser.parse(line);

代码运行后,我们发现分词的结果存储在变量query 。

Query

Query对应实现类BooleanQuery。分词之后的结果存储于变量clauses(Collections)中,里面的元素就是分词之后的每个单词即BooleanClause实例。

BooleanClause类有一个变量为query(TermQuery)–>term(Term),这个term就是我们的单词了。
在这里插入图片描述

Term

field:索引字段
bytes:单词字符串对应的byte[]

StandardAnalyzer

官方的标准分词器StandardAnalyzer,它使用了标准分词器对应的分词算法StandardTokenizer,然后再加上忽略大小写LowerCaseFilter和停用词StopFilter的过滤功能TokenFilter

java">@Override
  protected TokenStreamComponents createComponents(final String fieldName) {
    final Tokenizer src;
    if (getVersion().onOrAfter(Version.LUCENE_4_7_0)) {
      StandardTokenizer t = new StandardTokenizer();
      t.setMaxTokenLength(maxTokenLength);
      src = t;
    } else {
      StandardTokenizer40 t = new StandardTokenizer40();
      t.setMaxTokenLength(maxTokenLength);
      src = t;
    }
    TokenStream tok = new StandardFilter(src);
    tok = new LowerCaseFilter(tok);
    tok = new StopFilter(tok, stopwords);
    return new TokenStreamComponents(src, tok) {
      @Override
      protected void setReader(final Reader reader) {
        int m = StandardAnalyzer.this.maxTokenLength;
        if (src instanceof StandardTokenizer) {
          ((StandardTokenizer)src).setMaxTokenLength(m);
        } else {
          ((StandardTokenizer40)src).setMaxTokenLength(m);
        }
        super.setReader(reader);
      }
    };
  }

源码分析

java">QueryParser parser = new QueryParser(field, analyzer);
Query query = parser.parse(line);

QueryParser.parse是继承QueryParserBase源码如下:在这里插入图片描述
new FastCharStream(new StringReader(query)),应该就是把字符串转化为lucene优化过的字节流了;ReInit是重新初始化QueruParser

接下来是TopLevelQuery,然后看关键代码,我们可以直接跳到QueryBuilder.createFieldQuery
在这里插入图片描述

QueryBuilder.createFieldQuery

QueryBuilder这个实现类中,createFieldQuery会生成带有分词结果的Query对象。

为了方便理解,我们可以先看代码执行后,CachingTokenFilter会缓存分词结果,放在一个cache链表,里面的每个元素就是经过分词之后的每个单词。
在这里插入图片描述
最后,再把stream缓存的每一个单词转化为对应一个Query实例,这个方法就不细说了,有兴趣的可以自己去看源码
在这里插入图片描述
analyzeMultiBoolean这个方法其实就是如何将CachingTokenFilter的分词结果传输到BooleanQuery

-------------------------------继续看源码----------------------------------

首先,看第一部分代码,都是一些初始化,包括分词器Analyzer,还有缓存分词结果的CachingTokenFilter对象stream变量
在这里插入图片描述
然后,第二部分代码,stream.incrementToken()这是分词的重点,进入这个方法
在这里插入图片描述
进入了之后,我们可以看到,像我们上面看到的,会有一个cache链表来存储分词结果。然后,再转化为一个iterator
在这里插入图片描述
那么,显而易见,分词是在fillCache()这个方法块里完成的了。
在这里插入图片描述

StandardTokenizer

再深入研究,发现来到了StandardTokenizer类,这里我们需要知道scanner是实现类StandardTokenizerImpl,我们先看scanner.getText(termAtt)方法
在这里插入图片描述

StandardTokenizerImpl

scanner.getText(termAtt)这里的变量t,即传入的参数termAtt有一个属性termBuffer,是一个char[],看名字也就可以知道跟Term是类似的作用,存放单词的。可以看到,方法的功能是从另一个char数组,根据起始位置和长度来获取当前的单词。那么,其实完成分词的关键就是计算zzStartReadzzStartRead
在这里插入图片描述
这个两个成员变量的计算,跟踪源码,发现是在scanner.getNextToken()这里实现的,也就是StandardTokenizerImpl实现类的getNextToken方法了。所以,最关键的分词算法就是在这里实现,我们可以根据自己的实际情况设计自己的分词算法。

最后,由于根据上面提到的标准分词器StandardAnalyzer还使用忽略大小写和停用词的功能,所以,StandardTokenizerImpl分词之后的单词还会进行大小写处理和停用词过滤。
在这里插入图片描述
在这里插入图片描述
欢迎关注同名公众号:“我就算饿死也不做程序员”。
交个朋友,一起交流,一起学习,一起进步。在这里插入图片描述


http://www.niftyadmin.cn/n/1693501.html

相关文章

Lucene源码(二):文本相似度TF-IDF原理

Lucene中TF-IDF的计算公式与普通的TF-IDF不一样。学习之后,感觉Lucene的计算方法更加合理,考虑得更加周全。 q:query,即搜索内容,例如:github d:document,即文档内容,例…

Lucene源码(三):全文检索的底层原理

文章目录IndexSearchersearchAfterCollectorManagersearchcreateNormalizedWeightcreateWeightTermQuerycreateWeightTermWeightTFIDFSimilarityBooleanScorerLucene源码(一):分词器的底层原理Lucene源码(二):文本相似度TF-IDF原理核心代码是下面这几句。…

维特比(Viterbi)算法

算法思想 维特比(Viterbi)算法属于一种动态规划算法,目标在于寻找最优路径。我个人用得最多就是与BiLSTMCRF模型的结合,比如命名实体识别、分词等,计算了每个token的归一化概率矩阵和转移概率矩阵之后,最后…

Spring Boot项目技术入门级使用教程

前言 由于本人并没有经常使用Spring Boot项目,没有去阅读源码,此篇博客仅仅是入门级别的使用教程,为了在想简单使用Spring Boot项目时可以用上。 创建springboot项目 在IDEA安装插件:Spring Assistant。然后按平时的操作新建项…

条件随机场(CRF)的原理与实现

一、概率无向图模型 模型定义 又称马尔科夫随机场。设有联合概率分布P(Y),由无向图G(V,E)表示,结点V表示随机变量,边E表示随机变量之间的依赖关系。如果P(Y)满足成对、局部或全局马尔科夫性,就此联合概率分布为概率无向图模型。…

隐马尔科夫模型(HMM)模型训练:Baum-Welch算法

在上一篇博客中隐马尔科夫模型(HMM)原理详解,对隐马尔科夫模型的原理做了详细的介绍。今天,我们要对其中的模型训练算法Baum-Welch做一个实现,Baum-Welch算法可以在不知道状态序列的情况下,对模型的参数进行训练拟合。 这其实是非…

BERT等复杂深度学习模型加速推理方法——模型蒸馏

参考《Distilling the Knowledge in a Neural Network》Hinton等 蒸馏的作用 首先,什么是蒸馏,可以做什么? 正常来说,越复杂的深度学习网络,例如大名鼎鼎的BERT,其拟合效果越好,但伴随着推理…

布隆过滤器 (Bloom Filter):用于超大数据量时检索一个元素是否存在

相信大家在开发过程中,经常会遇到判断一个字符串(或其他类型的变量值)是否已经出现过的需求,这个时候一般使用HashMap可以解决,先将出现过的字符串存于HashMap对象的keySet中,下次只要判断HashMap对象的key…