过滤器在生产环境中应用也比较多。比如禁用词的过滤显示、推荐商品的过期设置等。
在编写时,需要在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(); }