关于使用Filter降低Lucene tf idf打分计算的调研
将query改成filter,lucene中有个QueryWrapperFilter性能比较差,所以基本上都须要自己写filter。包含TermFilter,ExactPhraseFilter,ConjunctionFilter,DisjunctionFilter。
附ExactPhraseFilter和ut代码:
import java.io.IOException;
import java.util.ArrayList;
import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.index.DocsAndPositionsEnum;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermContext;
import org.apache.lucene.index.TermState;
import org.apache.lucene.index.Terms;
import org.apache.lucene.index.TermsEnum;
import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.DocIdSetIterator;
import org.apache.lucene.search.Filter;
import org.apache.lucene.util.ArrayUtil;
import org.apache.lucene.util.Bits;
// A fake to lucene phrase query, but far simplified.
public class ExactPhraseFilter extends Filter {
protected final ArrayList<Term> terms = new ArrayList<Term>();
protected final ArrayList<Integer> positions = new ArrayList<Integer>();
protected String fieldName;
public void add(Term term) {
if (terms.size() == 0) {
fieldName = term.field();
} else {
assert fieldName == term.field();
}
positions.add(Integer.valueOf(terms.size()));
terms.add(term);
}
@Override
public DocIdSet getDocIdSet(AtomicReaderContext context, Bits acceptDocs) throws IOException
{
return new ExactPhraseDocIdSet(context, acceptDocs);
}
static class PostingAndFreq implements Comparable<PostingAndFreq> {
DocsAndPositionsEnum posEnum;
int docFreq;
int position;
boolean useAdvance;
int posFreq = 0;
int pos = -1;
int posTime = 0;
public PostingAndFreq(DocsAndPositionsEnum posEnum, int docFreq, int position, boolean useAdvance) {
this.posEnum = posEnum;
this.docFreq = docFreq;
this.position = position;
this.useAdvance = useAdvance;
}
@Override
public int compareTo(PostingAndFreq other) {
if (docFreq != other.docFreq) {
return docFreq - other.docFreq;
}
if (position != other.position) {
return position - other.position;
}
return 0;
}
}
protected class ExactPhraseDocIdSet extends DocIdSet {
protected final AtomicReaderContext context;
protected final Bits acceptDocs;
protected final PostingAndFreq[] postings;
protected boolean noDocs = false;
public ExactPhraseDocIdSet(AtomicReaderContext context, Bits acceptDocs) throws IOException {
this.context = context;
this.acceptDocs = acceptDocs;
Terms fieldTerms = context.reader().fields().terms(fieldName);
// TermContext states[] = new TermContext[terms.size()];
postings = new PostingAndFreq[terms.size()];
TermsEnum te = fieldTerms.iterator(null);
for (int i = 0; i < terms.size(); ++i) {
final Term t = terms.get(i);
// states[i] = TermContext.build(context, terms.get(i), true);
// final TermState state = states[i].get(context.ord);
if (!te.seekExact(t.bytes(), true)) {
noDocs = true;
return;
}
if (i == 0) {
postings[i] = new PostingAndFreq(te.docsAndPositions(acceptDocs, null, 0), te.docFreq(), positions.get(i), false);
} else {
postings[i] = new PostingAndFreq(te.docsAndPositions(acceptDocs, null, 0), te.docFreq(), positions.get(i), te.docFreq() > 5 * postings[0].docFreq);
}
}
ArrayUtil.mergeSort(postings);
for (int i = 1; i < terms.size(); ++i) {
postings[i].posEnum.nextDoc();
}
}
@Override
public DocIdSetIterator iterator() throws IOException
{
if (noDocs) {
return EMPTY_DOCIDSET.iterator();
} else {
return new ExactPhraseDocIdSetIterator(context, acceptDocs);
}
}
protected class ExactPhraseDocIdSetIterator extends DocIdSetIterator {
protected int docID = -1;
public ExactPhraseDocIdSetIterator(AtomicReaderContext context, Bits acceptDocs) throws IOException {
}
@Override
public int nextDoc() throws IOException {
while (true) {
// first (rarest) term
final int doc = postings[0].posEnum.nextDoc();
if (doc == DocIdSetIterator.NO_MORE_DOCS) {
// System.err.println("END");
return docID = doc;
}
// non-first terms
int i = 1;
while (i < postings.length) {
final PostingAndFreq pf = postings[i];
int doc2 = pf.posEnum.docID();
if (pf.useAdvance) {
if (doc2 < doc) {
doc2 = pf.posEnum.advance(doc);
}
} else {
int iter = 0;
while (doc2 < doc) {
if (++iter == 50) {
doc2 = pf.posEnum.advance(doc);
} else {
doc2 = pf.posEnum.nextDoc();
}
}
}
if (doc2 > doc) {
break;
}
++i;
}
if (i == postings.length) {
// System.err.println(doc);
docID = doc;
// return docID;
if (containsPhrase()) {
return docID;
}
}
}
}
@Override
public int advance(int target) throws IOException {
throw new IOException();
}
private boolean containsPhrase() throws IOException {
int index = -1;
int i = 0;
PostingAndFreq pf;
// init.
for (i = 0; i < postings.length; ++i) {
postings[i].posFreq = postings[i].posEnum.freq();
postings[i].pos = postings[i].posEnum.nextPosition() - postings[i].position;
postings[i].posTime = 1;
}
while (true) {
pf = postings[0];
// first term.
while (pf.pos < index && pf.posTime < pf.posFreq) {
pf.pos = pf.posEnum.nextPosition() - pf.position;
++pf.posTime;
}
if (pf.pos >= index) {
index = pf.pos;
} else if (pf.posTime == pf.posFreq) {
return false;
}
// other terms.
for (i = 1; i < postings.length; ++i) {
pf = postings[i];
while (pf.pos < index && pf.posTime < pf.posFreq) {
pf.pos = pf.posEnum.nextPosition() - pf.position;
++pf.posTime;
}
if (pf.pos > index) {
index = pf.pos;
break;
}
if (pf.pos == index) {
continue;
}
if (pf.posTime == pf.posFreq) {
return false;
}
}
if (i == postings.length) {
return true;
}
}
}
@Override
public int docID()
{
return docID;
}
}
}
}
UT:
import java.io.IOException;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.codecs.Codec;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.TextField;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.search.ConstantScoreQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.dp.arts.lucenex.codec.Dp10Codec;
public class ExactPhraseFilterTest
{
final Directory dir = new RAMDirectory();
@BeforeTest
public void setUp() throws IOException {
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_40);
IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_40, analyzer);
iwc.setOpenMode(OpenMode.CREATE);
iwc.setCodec(Codec.forName(Dp10Codec.DP10_CODEC_NAME));
IndexWriter writer = new IndexWriter(dir, iwc);
addDocument(writer, "新疆烧烤"); // 0
addDocument(writer, "啤酒"); // 1
addDocument(writer, "烤烧"); // 2
addDocument(writer, "烧烧烧"); // 3
addDocument(writer, "烤烧中华烧烤"); // 4
writer.close();
}
private void addDocument(IndexWriter writer, String str) throws IOException {
Document doc = new Document();
doc.add(new TextField("searchkeywords", str, Store.YES));
writer.addDocument(doc, new StandardAnalyzer(Version.LUCENE_40));
}
@AfterTest
public void tearDown() throws IOException
{
this.dir.close();
}
@Test
public void test1() throws IOException
{
IndexReader reader = DirectoryReader.open(dir);
IndexSearcher searcher = new IndexSearcher(reader);
ExactPhraseFilter pf = new ExactPhraseFilter();
pf.add(new Term("searchkeywords", "烧"));
pf.add(new Term("searchkeywords", "烤"));
Query query = new ConstantScoreQuery(pf);
TopDocs results = searcher.search(query, 20);
assert results.totalHits == 2;
assert results.scoreDocs[0].doc == 0;
assert results.scoreDocs[1].doc == 4;
searcher.getIndexReader().close();
}
}
关于使用Filter降低Lucene tf idf打分计算的调研的更多相关文章
- Lucene默认的打分算法——ES默认
改变Lucene的打分模型 随着Apache Lucene 4.0版本在2012年的发布,这款伟大的全文检索工具包终于允许用户修改默认的基于TF/IDF原理的打分算法.Lucene API变得更加容易 ...
- 文本分类学习(三) 特征权重(TF/IDF)和特征提取
上一篇中,主要说的就是词袋模型.回顾一下,在进行文本分类之前,我们需要把待分类文本先用词袋模型进行文本表示.首先是将训练集中的所有单词经过去停用词之后组合成一个词袋,或者叫做字典,实际上一个维度很大的 ...
- 25.TF&IDF算法以及向量空间模型算法
主要知识点: boolean model IF/IDF vector space model 一.boolean model 在es做各种搜索进行打分排序时,会先用boolean mo ...
- TF/IDF(term frequency/inverse document frequency)
TF/IDF(term frequency/inverse document frequency) 的概念被公认为信息检索中最重要的发明. 一. TF/IDF描述单个term与特定document的相 ...
- 基于TF/IDF的聚类算法原理
一.TF/IDF描述单个term与特定document的相关性TF(Term Frequency): 表示一个term与某个document的相关性. 公式为这个term在document中出 ...
- 使用solr的函数查询,并获取tf*idf值
1. 使用函数df(field,keyword) 和idf(field,keyword). http://118.85.207.11:11100/solr/mobile/select?q={!func ...
- TF/IDF计算方法
FROM:http://blog.csdn.net/pennyliang/article/details/1231028 我们已经谈过了如何自动下载网页.如何建立索引.如何衡量网页的质量(Page R ...
- tf–idf算法解释及其python代码实现(下)
tf–idf算法python代码实现 这是我写的一个tf-idf的简单实现的代码,我们知道tfidf=tf*idf,所以可以分别计算tf和idf值在相乘,首先我们创建一个简单的语料库,作为例子,只有四 ...
- tf–idf算法解释及其python代码实现(上)
tf–idf算法解释 tf–idf, 是term frequency–inverse document frequency的缩写,它通常用来衡量一个词对在一个语料库中对它所在的文档有多重要,常用在信息 ...
随机推荐
- table中td 内容超长 自动折行 (含字母数字文字)
<table style="width:100%;table-layout:fixed;"> //列宽由表格宽度和列宽度设定 <thead> <th& ...
- 类class思维导图
- js原型及原型链解析
js原型.原型链 这几天闲了看了下js的原型,以下内容为个人理解,如有错误,尽请指正. 首先,明确一点:js中的对象分为普通对象和函数对象,一般我们自定义的可以被new的函数称作函数对象,另外js内置 ...
- Docker学习(一): 基本概念
特别声明: 博文主要是学习过程中的知识整理,以便之后的查阅回顾.部分内容来源于网络(如有摘录未标注请指出).内容如有差错,也欢迎指正! =============系列文章============= 1 ...
- 给<input>文本框添加灰色提示文字
value="你的提示文字" onFocus="if(value==defaultValue){value='';this.style.color='#000'}&quo ...
- 撩课-Python-每天5道面试题-第9天
一. Python程序中, 文件的处理步骤是什么? 打开 open("文件","模式") 读写 2.1 读 f.read(字节数) 字节数默认是文件内容长度 下 ...
- 01-Web客户端与服务器详解
1.CS与BS 软件使用方式上两种划分 C/S架构 Client/ServerPC客户端.服务器架构 特点: 在服务器当中就主要是一个数据库,把所有的业务逻辑以及界面都交给客户端完成 优点: 较为安全 ...
- hdu 3474 Necklace 单调队列
Necklace Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Su ...
- Python Django 路由分发
mysite1 为一个django工程 cmdb为一个项目 dashboard为一个项目 在mysite1工程下的urls.py中定义如下: from django.conf.urls import ...
- js得到数组的下标值
<script type="text/javascript"> var arr = [1,2,3,4,5,6,2,4,55]; for(var i=0; $i<a ...