采用Lucene建设企业级全文检索系统,通常需要根据用户权限,检索有权限阅读的文档。本文提出扩展Filter的方式自定义过滤全文检索结果,实现权限过滤功能。 在企业文档管理系统中,通常需要对索引检索结果进行过滤。Lucene有很多内置的过滤器,可以方便进行检索结果过滤: QueryFilter:过滤内容是符合另外一个查询。相当于两个Query的And。 RangFilter:结果必须在一定范围之内。 ChainedFilter:过滤链。几种Filter按照一定的逻辑顺序组合。 CachingWrapperFilter:增加指定过滤器的cache功能。QueryFilter本身自带Cache,RangFilter不带。Cache指对相同的IndexSearcher实例有效,在一个IndexSearcher使用了Cahce过滤器后,再另外一个IndexSearcher实例使用,Cache是不起作用的。另,FilterQuery是一种带过滤的查询,效果等同于过滤器,这种查询可用于BooleanQuery中。
有时候根据具体的需求,有些记录对于一些用户是不可见的,此时就要使用过滤器来防止不合法的用户看到不应该看到的记录。如在企业文档管理系统中,通常需要对用户可阅读的文档进行权限校验。
这里使用了Lucene提供的Filter机制,实现自定义的filter ,根据用户的所在部门,对索引库中的文件进行过滤。返回用户拥有阅读权限的文档。
1 .自定义的Filter实现如下:
public class SearchFilesFilter extends Filter {
//存放当前用户能访问的文件所属的组织ID列表 ,存放orgId值列表
private String[] permList;
//设置权限参数列表,将orgId值传入SearchFilesFilter
public SearchFilesFilter(String[] permissions) {permList = permissions; }
//实现Filter的BitSet方法,根据权限校验要求设置BitSet的值,以过滤检索结果
public BitSet bits(IndexReader reader) throws IOException {
//构造返回值BitSet, BitSet集合中每一个变量的值为缺省值false
BitSet bits = new BitSet(reader.maxDoc());
//遍历配置权限信息(orgId列表)
for (int i = 0; i < permList.length; i++) {
String orgid = permList[i];
if (orgid != null) {
//构造orgid域对应的Term
Term t = new Term("orgid", orgid);
//获取所有包含该Term的Documents枚举变量 TermDocs
TermDocs termDocs = reader.termDocs(t);
//遍历TermDocs枚举变量中其他Document对象
while (termDocs.next()) {
//设置BitSet中 termDocs.doc() 对应的值为true
bits.set(termDocs.doc());
}
}
}
return bits;
}
2. 建立索引时加入权限信息:
在本文档附带的代码中,以下代码展示了如何在索引中加入权限信息。
在IndexFilesFilter中,设置了10个组织ID,随机获取其中一个ORGID,写入文件索引中。其代码如下:
if (doc != null) {
Field FieldName = new Field("name", file.getName(), Field.Store.YES, Field.Index.TOKENIZED,Field.TermVector.WITH_POSITIONS_OFFSETS);
doc.add(FieldName);
Field FieldPath = new Field("path", file.getPath(), Field.Store.YES, Field.Index.TOKENIZED,Field.TermVector.WITH_POSITIONS_OFFSETS);
doc.add(FieldPath);
doc.add(new Field("modified",DateTools.timeToString(file.lastModified(), DateTools.Resolution.MINUTE),Field.Store.YES, Field.Index.UN_TOKENIZED));
String[] orgList = new String[10];
orgList[1]="5117";
orgList[2]="5097";
orgList[3]="7115";
orgList[4]="4453";
orgList[5]="3897";
orgList[6]="1767";
orgList[7]="2667";
orgList[8]="9447";
orgList[9]="8227";
orgList[0]="3117";
Random r = new java.util.Random();//为演示需要,随机获取组织ORGID
int k = r.nextInt(10);
String orgId = orgList[k];
Field FieldOrgId = new Field("orgid", orgId, Field.Store.YES, Field.Index.UN_TOKENIZED,Field.TermVector.WITH_POSITIONS_OFFSETS);
doc.add(FieldOrgId); //加入组织信息ORGID
writer.addDocument(doc); //建立索引
}
3. 使用自定义Filter实现权限过滤:
有了前面的Filter和带权限信息的全文索引,我们可以很方便的实现对检索结果的过滤,代码如下:
public static void main(String[] args) throws Exception {
Hits hits = null;
String queryString = "解决方案";
Query query = null;
String indexHome = IndexFiles.INDEX_HOME;
IndexSearcher searcher = new IndexSearcher(indexHome);
IndexFiles index = new IndexFiles();
try {
QueryParser qp = new QueryParser("body", index.analyzer);
query = qp.parse(queryString);
String[] orgList = new String[10];
orgList[0]="5097"; orgList[1]="5117";
Filter filter = new SearchFilesFilter(orgList); //构造自定义Filter对象
hits = searcher.search(query, filter); //使用自定义Filter对检索结果进行过滤
// hits = searcher.search(query );
if (hits.length() > 0) {
System.out.println("找到:" + hits.length() + " 个结果!");
for (int i = 0; i < hits.length(); i++) {
Document doc = hits.doc(i);
System.out.println("** 结果=" + (i+1));
System.out.println("score=" + hits.score(i));
System.out.println("name=" + doc.get("name"));
System.out.println("orgid=" + doc.get("orgid"));
}
}
} catch (ParseException e) {
}
这样,就只检索出orgid为5097和5117的文档。 |