过滤器在生产环境中应用也比较多。比如禁用词的过滤显示、推荐商品的过期设置等。
在编写时,需要在incrementToken添加自己的过滤规则。,下面的demo是针对同义词编写的过滤。过滤器的编写也可以参照org.apache.lucene.analysis.cn.ChineseFilter进行编写。
使用自定义过滤器进行查询
package com.johnny.lucene04.advance_search;
import java.io.IOException;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
public class CustomFilter {
/**
* 用户自定义Filter,通过Filter进行数据过滤,在这里可以通过ioc注入方式或者配置文件的方式针对多种情况添加不通的过滤器
*/
public void searchByCustomFilter(){
try {
IndexSearcher search = new IndexSearcher(DirectoryReader.open(FileIndexUtils.getDirectory()));
Query q = new TermQuery(new Term("content","java"));
TopDocs tds = search.search(q, new MyIDFilter(new FilterAccessor() {
@Override
public String[] needOperateValues() {
/**显示ID
String[] ids = new String[]{"1","2","3","4","5"};
return ids;
**/
/**按照fileName进行展示**/
String[] fileNames = new String[]{"MySameAnalyzer.txt","MySameAnalyzer副本 13.txt"};
return fileNames;
}
@Override
public String getField() {
/** String field = "id"; **/
String field = "fileName";
return field;
}
@Override
public boolean hasSet() {
return true;
}
}),200);
for(ScoreDoc sd:tds.scoreDocs) {
Document d = search.doc(sd.doc);
System.out.println(sd.doc+":("+sd.score+")" +
"["+d.get("fileName")+"【"+d.get("path")+"】--->"+
d.get("size")+"------------>"+d.get("id"));
}
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.johnny.lucene04.advance_search;
/**
* 定义数据处理的接口,用来提高数据处理的通用性
* 使用情况参见customFilter和MyIdFilter
* @author Johnny
*
*/
public interface FilterAccessor {
public String[] needOperateValues();//获取需要处理的元素
public String getField();//需要进行过滤的字段(也就是所谓的域)
/**
* 如果返回值为true,表示needOperateValues需要进行显示,
* 如果返回值为false,表示needOperateValues需要进行隐藏
**/
public boolean hasSet();//设定需要处理的数据是否通过过滤
}
自定义过滤器
package com.johnny.lucene04.advance_search;
import java.io.IOException;
import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.index.DocsEnum;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermContext;
import org.apache.lucene.index.TermsEnum;
import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.TermRangeFilter;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.OpenBitSet;
/**
* 自定义过滤器,每次查询都会进行过滤,所以最好做成单例,保存在内存中。
* @author Johnny
*
*/
public class MyIDFilter extends Filter {
private FilterAccessor filterAccessor;
public MyIDFilter(FilterAccessor filterAccessor){
this.filterAccessor = filterAccessor;
}
/**
* 对于特价商品的Filter,可以反过来处理,将符合条件的设置为1,不符合条件的默认即可(默认为0)
*/
@Override
public DocIdSet getDocIdSet(AtomicReaderContext context, Bits acceptDocs)
throws IOException {
//openBitset是docIdSet的实现类,obs默认值都是0,0表示不显示,1表示显示
//获取所有的docId
OpenBitSet obs = new OpenBitSet(context.reader().maxDoc());
//int base = context.docBase;//段的相对基数,保证多个段时相对位置正确
if(filterAccessor.hasSet()){
set(context, obs);
}else{
clear(context, obs);
}
return obs;
}
/**
* 用来设置docidset值为1,证明通过过滤
*/
private void set(AtomicReaderContext context,OpenBitSet obs){
//设置不通过过滤ID的位置的值为0
for(String id:filterAccessor.needOperateValues()){
try {
DocsEnum de = context.reader().termDocsEnum(new Term(filterAccessor.getField(),id));//必须是唯一的不重复
//保证是单个不重复的term,如果重复的话,默认会取第一个作为返回结果集,分词后的term也不适用自定义term
if(de.nextDoc()!=-1){
obs.set(de.docID());//将符合条件的doc的值设置为1,默认为0
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 用来设置docidset值为0,证明不通过过滤
*/
private void clear(AtomicReaderContext context,OpenBitSet obs){
try{
/** //先把元素填满 //set的值为docId,这里设置完成后,就会将值设置为1,表示会通过过滤**/
obs.set(0,context.reader().maxDoc());
for(String id:filterAccessor.needOperateValues()){
DocsEnum de = context.reader().termDocsEnum(new Term(filterAccessor.getField(),id));//必须是唯一的不重复
//保证是单个不重复的term,如果重复的话,默认会取第一个作为返回结果集,分词后的term也不适用自定义term
if(de.nextDoc()!=-1){
obs.clear(de.docID());;//将符合条件的doc的值设置为0,默认为1
}
}
}catch(IOException e){
e.printStackTrace();
}
}
}
测试方法:
@Test
public void testCustomFilter(){
CustomFilter cf = new CustomFilter();
cf.searchByCustomFilter();
}