我发现自己很难尝试开发基于现有Lucene TokenFilter类的代码。这些类似乎都被声明为final,这意味着我不能将它们子类化,而且我不确定我是否看到了它的动机。
但我需要做的一件主要事情我认为我已经成功了。我想知道是否有更清洁的方法来完成我所追求的目标。
具体要求是能够建立一组代表令牌的“保留词”,即使在存在通常会删除它们的令牌过滤器的情况下也应该在令牌流中存活。为此,我只关心子类FilteringTokenFilter
的过滤器。
所以我的方法是实现一个包含PreservingFilterWrapper
实例的类FilteringTokenFilter
。 (PreserveAttribute
是由上游过滤器建立的属性,用于标识与保留字匹配的标记。)
public class PreservingFilterWrapper extends FilteringTokenFilter {
private final FilteringTokenFilter wrappedFilter;
private final Method wrappedFilterAccept;
private final TokenStream upstream;
public PreservingFilterWrapper(Version version, FilteringTokenFilter wrappedFilter, TokenStream upstream) {
super(version, upstream);
this.wrappedFilter = wrappedFilter;
try {
this.wrappedFilterAccept = wrappedFilter.getClass().getDeclaredMethod("accept");
wrappedFilterAccept.setAccessible(true);
} catch (Exception e) {
throw new RuntimeException(e);
}
this.upstream = upstream;
}
private final PreserveAttribute preserveAtt = addAttribute(PreserveAttribute.class);
@Override
protected boolean accept() throws IOException {
if (preserveAtt.isPreserved()) {
return true;
} else {
try {
return (Boolean) wrappedFilterAccept.invoke(wrappedFilter);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
这很有效。但是我真的不高兴违反声明的保护措施(使用getDeclaredMethod
来访问包装过滤器的accept()
方法,该方法被声明为protected
)。然后,我也很难理解为什么这个方法需要protected
,因为我理解为什么所有这些过滤器类都需要final
。
我对此处所需的奇怪管道也不感到兴奋:包装过滤器和包装器都需要使用相同的TokenStream
对象进行实例化,以便它们共享属性实例。但是,包装过滤器实际上并不像过滤器 - 例如,它的incrementToken()
方法永远不会被调用。我只想访问其accept()
逻辑。如果这些类不是最终的,当然,我可以继承我想要使用的过滤器,这一切都很容易。
因此我的整体质疑。我只是错过了一种更清晰的方法来解决这个问题吗?或者Lucene的保护真的迫使我的手?如果是后者,是否有充分的理由进行这些保护,或者在某些后期版本中可能会放松一些游戏工作?
答案 0 :(得分:0)
当然,关于创建一个包装类以撤消对所选单词的过滤的部分听起来对我来说是一个很好的方法,尽管你可能会看一下学术文献,看看是否有人提出了一种更优雅的处理方法这个问题。
至于保护措施,我无法真正与那些人交谈 - 对我来说,制作太多“最终”或“私人”的东西似乎总是在完成我的单元测试时会导致悲伤。