Lucene查找过程源码分析

Lucene查找过程源码分析

从最简单的开始分析:根据某个字段搜索到匹配的文档,这个过程就像是从词典找到一个拼音同音字组成的词语有哪些一样,主要分为两步

1、从字典的检索目录找到所有对应的页码

2、找到对应页码查看其组成的词语有哪些

数据

// 数据
Product product_1 = new Product(1, "华为手机", 3000, 10, "华为.jpg", "华为", "300*300", 5);
Product product_2 = new Product(2, "苹果手机", 8000, 30, "苹果.jpg", "苹果", "500*500", 15);

// 指定字段为name
QueryParser queryParser = new QueryParser("name", analyzer);
// 指定内容为手机
Query query = queryParser.parse("手机");
// 搜索,取10条
TopDocs topDocs_10 = indexSearcher.search(query, 10);

从上面的伪代码可以到两份数据,分别是两个品牌的手机数据,我们希望找到所有name为手机的文档(这里假定name字段被分词为华为 苹果 手机三个term)

查找

IndexSearcher

IndexSearcher是整个搜索过程的核心类。它利用IndexReader读取索引数据,并根据查询条件执行搜索。

search()

public void search(Query query, Collector results)
  throws IOException {
  query = rewrite(query);
  search(leafContexts, createWeight(query, results.needsScores(), 1), results);
}
Weight

Weight是Lucene中一个抽象类,它代表了查询的“权重”。在搜索过程中,每个查询都会生成一个Weight对象,它负责处理查询的具体执行逻辑和评分机制。
createWeight()

 public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException {
    final IndexReaderContext context = searcher.getTopReaderContext();
    final TermContext termState;
    if (perReaderTermState == null
        || perReaderTermState.wasBuiltFor(context) == false) {
      if (needsScores) {
        // 构建tremState加速查找
        termState = TermContext.build(context, term);
      }
      ...  
  }

termState非常重要,实际构建完毕后就相当于已经找到了term对应的文档信息

public static TermContext build(IndexReaderContext context, Term term)
    throws IOException {
  ...
  for (final LeafReaderContext ctx : context.leaves()) {
    if (terms != null) {
      final TermsEnum termsEnum = terms.iterator();
      // 根据term搜索相关文档
      if (termsEnum.seekExact(bytes)) { 
        final TermState termState = termsEnum.termState();
        perReaderTermState.register(termState, ctx.ord, termsEnum.docFreq(), termsEnum.totalTermFreq());
      }
    }
  }
  return perReaderTermState;
}
SegmentTermsEnum

SegmentTermsEnum 是 Lucene 中用于遍历和查找术语(term)的一个类,特别是在索引的某个段(segment)中。它是 Lucene 的 TermsEnum 的一个实现,主要用于对特定的索引段中的术语进行精确定位和迭代。

seekCeil()

代码省略
...

我们知道term字典在Lucene中实际使用FST进行存储,这里方法中便是尝试从所有词项(例子的name的词项为:华为 苹果 手机)中逐个匹配是否存在,这样我们就确定了term存在于哪些文档

TermQuery

TermQuery它用于精确匹配单个术语(term)。在 Lucene 中,术语通常指的是一个字段的某个具体的值,比如一个词语或数字。TermQuery 是最基本的查询类型之一,适用于需要查找完全匹配的文档的场景

scorer()

public Scorer scorer(LeafReaderContext context) throws IOException {
 // 找到term的对应的迭代器
  final TermsEnum termsEnum = getTermsEnum(context);
  if (termsEnum == null) {
    return null;
  }
  // 找到term索引的迭代器
  PostingsEnum docs = termsEnum.postings(null, needsScores ? PostingsEnum.FREQS : PostingsEnum.NONE);
  assert docs != null;
  return new TermScorer(this, docs, similarity.simScorer(stats, context));
}

termsEnum这个词项的迭代器实际上是从上面的termState获取的,拿到了它就相当于拿到了所有我们查找文档的基本信息

PostingsEnum则可以认为是对文档的索引信息迭代器(还包含其他信息),拿到了它就相当于我们明确了查找文档的准确信息

总结

到这里,一个ES精准查询的查找部分的主脉络就算结束了,但实际的查询会更为复杂,包括包含多字段时需要进行数据的合并,根据文档的分数进一步筛选,范围查询、模糊查询等复杂的情况

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值