【Lucene】SimScorer

SimScorer 就是 Lucene 中真正给“某个 term 在一篇文档里的打分”算分的最小执行单元,被 `TermScorer` 等 scorer 调用,完成 TF-IDF、BM25 等算法的实际数值计算。

---

1. 它在哪?  

- 定义在 `org.apache.lucene.search.similarities.Similarity.SimScorer`(内部静态抽象类)。  

- 每个 `Similarity` 实现(如 `BM25Similarity`)都会创建自己的 `SimScorer` 子类(如 `BM25Scorer`)。

2. 它做什么?  

对外只有两个核心动作:  

1. score(float freq, long norm)

   根据“词频 freq”和“字段长度编码 norm”立即返回该 term 在该文档的分数。  

2. explain(...)

   生成人类可读的 `Explanation`,告诉你为啥得这个分。

3. 什么时候被用到?  

查询阶段:  

- `IndexSearcher` → `TermQuery$TermWeight.scorer()` → `TermScorer` → `TermScorer.score()` 内部调用 `simScorer.score(freq, norm)`。

也就是说,每匹配一篇文档,都会跑一次 `SimScorer.score(...)`。

4. 用 BM25 举例  

```java

// 在 BM25Similarity 内部

public final SimScorer simScorer(...) {

    ...

    return new BM25Scorer(boost, k1, b, idf, avgdl, cache);

}

```

`BM25Scorer.score(freq, norm)` 就是标准 BM25 公式:  

```java

return weight * (freq / (freq + K(norm)));

```

其中 `K(norm)` 已经预先缓存到 `cache[]` 中,保证每次打分只做一次乘除。

---

✅ 一句话记住  

> SimScorer = Lucene 相似度算法的“微积分”:给定词频和文档长度,立刻吐出该 term 的得分。

好的,下面是一个基于Lucene 8.11版本的自评分搜索系统的实现流程: 1. 创建索引 首先,需要创建一个索引,并将需要搜索的文档添加到索引中。可以使用Lucene提供的IndexWriter类来实现。 ```java IndexWriterConfig config = new IndexWriterConfig(new StandardAnalyzer()); IndexWriter writer = new IndexWriter(FSDirectory.open(indexDir), config); Document doc1 = new Document(); doc1.add(new StringField("id", "1", Field.Store.YES)); doc1.add(new TextField("title", "Lucene in Action", Field.Store.YES)); doc1.add(new TextField("content", "Lucene is a full-text search library in Java.", Field.Store.YES)); writer.addDocument(doc1); Document doc2 = new Document(); doc2.add(new StringField("id", "2", Field.Store.YES)); doc2.add(new TextField("title", "Java Programming", Field.Store.YES)); doc2.add(new TextField("content", "Java is a popular programming language.", Field.Store.YES)); writer.addDocument(doc2); writer.close(); ``` 2. 搜索文档 使用Lucene提供的IndexSearcher类进行文档搜索,可以使用QueryParser类将用户输入的搜索关键字解析成Query对象。 ```java IndexReader reader = DirectoryReader.open(FSDirectory.open(indexDir)); IndexSearcher searcher = new IndexSearcher(reader); QueryParser parser = new QueryParser("content", new StandardAnalyzer()); Query query = parser.parse("Java"); TopDocs topDocs = searcher.search(query, 10); ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc scoreDoc : scoreDocs) { Document doc = searcher.doc(scoreDoc.doc); System.out.println(doc.get("title")); System.out.println(doc.get("content")); System.out.println(scoreDoc.score); } reader.close(); ``` 3. 自定义评分算法 可以通过实现自定义的Similarity类来实现自定义评分算法。在Similarity类中,需要实现两个方法:`computeNorm(FieldInvertState state)`和`computeWeight(float boost, CollectionStatistics collectionStats, TermStatistics... termStats)`。 - `computeNorm(FieldInvertState state)`方法用于计算文档的归一化因子,影响文档的评分。可以根据需要实现自定义的归一化因子计算逻辑。 - `computeWeight(float boost, CollectionStatistics collectionStats, TermStatistics... termStats)`方法用于计算查询的权重,影响文档的评分。可以根据需要实现自定义的查询权重计算逻辑。 ```java public class CustomSimilarity extends Similarity { @Override public long computeNorm(FieldInvertState state) { // 自定义归一化因子计算逻辑 return state.getLength(); } @Override public SimWeight computeWeight(float boost, CollectionStatistics collectionStats, TermStatistics... termStats) { // 自定义查询权重计算逻辑 return new CustomSimWeight(boost, collectionStats, termStats); } @Override public SimScorer simScorer(SimWeight weight, LeafReaderContext context) throws IOException { // 自定义评分器实现 return new CustomSimScorer(weight, context); } } public class CustomSimWeight extends SimWeight { public CustomSimWeight(float boost, CollectionStatistics collectionStats, TermStatistics... termStats) { super(boost, collectionStats, termStats); } @Override public float getValueForNormalization() { return 1.0f; } @Override public void normalize(float queryNorm, float boost) { // 不进行归一化 } } public class CustomSimScorer extends SimScorer { public CustomSimScorer(SimWeight weight, LeafReaderContext context) throws IOException { super(weight, context); } @Override public float score(int doc, float freq) throws IOException { // 自定义评分逻辑 return freq; } @Override public float computeSlopFactor(int distance) { return 1.0f; } @Override public float computePayloadFactor(int doc, int start, int end, BytesRef payload) { return 1.0f; } } ``` 4. 使用自定义评分算法进行搜索 将自定义的Similarity类注册到IndexSearcher中,即可使用自定义的评分算法进行搜索。 ```java IndexReader reader = DirectoryReader.open(FSDirectory.open(indexDir)); IndexSearcher searcher = new IndexSearcher(reader); searcher.setSimilarity(new CustomSimilarity()); QueryParser parser = new QueryParser("content", new StandardAnalyzer()); Query query = parser.parse("Java"); TopDocs topDocs = searcher.search(query, 10); ScoreDoc[] scoreDocs = topDocs.scoreDocs; for (ScoreDoc scoreDoc : scoreDocs) { Document doc = searcher.doc(scoreDoc.doc); System.out.println(doc.get("title")); System.out.println(doc.get("content")); System.out.println(scoreDoc.score); } reader.close(); ``` 以上是一个基于Lucene 8.11版本的自评分搜索系统的实现流程。需要注意的是,具体实现中可能还需要根据实际需求进行一些调整和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值