使用现场桥接器实现Lucene分析仪
我想以一种能够很好地使用现场桥接和手动搜索的方式实现lucene分析器。理想情况下,我希望尽可能少的代码重复 我知道大多数教程都会告诉您使用@AnalyzerDef annotation初始化分析仪,虽然我这样做并使一切正常,但我无法在FieldBridges中创建字段以尊重分析仪。(使用luceneoptions.addFieldToDocument创建) 我试图找到另一种方法,但文档很少 这就是我提出的(为了保持文章简短,一些代码已经被编辑,但如果需要,我会发布更多。): 创建分析器:使用现场桥接器实现Lucene分析仪,lucene,hibernate-search,Lucene,Hibernate Search,我想以一种能够很好地使用现场桥接和手动搜索的方式实现lucene分析器。理想情况下,我希望尽可能少的代码重复 我知道大多数教程都会告诉您使用@AnalyzerDef annotation初始化分析仪,虽然我这样做并使一切正常,但我无法在FieldBridges中创建字段以尊重分析仪。(使用luceneoptions.addFieldToDocument创建) 我试图找到另一种方法,但文档很少 这就是我提出的(为了保持文章简短,一些代码已经被编辑,但如果需要,我会发布更多。): 创建分析器:
public static org.apache.lucene.analysis.Analyzer getEnglishWordAnalyser() {
org.apache.lucene.analysis.Analyzer analyser = null;
try {
analyser = CustomAnalyzer.builder()
.addCharFilter(HTMLStripCharFilterFactory.class)
.addCharFilter(MappingCharFilterFactory.class, getMappingSettings())
.withTokenizer(StandardTokenizerFactory.class)
.addTokenFilter(StandardFilterFactory.class)
.addTokenFilter(LowerCaseFilterFactory.class)
.addTokenFilter(SnowballPorterFilterFactory.class, getSnowballPorterSettings())
.addTokenFilter(SynonymFilterFactory.class, getSynonymSettings())
.addTokenFilter(ASCIIFoldingFilterFactory.class)
.addTokenFilter(PhoneticFilterFactory.class, getPhoneticSettings())
.addTokenFilter(StopFilterFactory.class, getStopSettings())
.build();
} catch (IOException ex) {
logger.info("[SearchConfig] [englishWordAnalyser] Failed to create components", ex);
}
return analyser;
}
protected StringField createStringField(String name, String value, LuceneOptions luceneOptions) {
final StringField field = new StringField(name, value, luceneOptions.getStore());
final Analyzer analyzer = SearchConfig.getEnglishWordAnalyser();
try {
final TokenStream tokenStream = analyzer.tokenStream(name, new StringReader(value));
tokenStream.reset();
field.setBoost(luceneOptions.getBoost());
field.setTokenStream(tokenStream);
field.setStringValue(value);
tokenStream.end();
tokenStream.close();
} catch (IOException e) {
e.printStackTrace();
}
analyzer.close();
return field;
}
使用Analyzer创建字段:
public static org.apache.lucene.analysis.Analyzer getEnglishWordAnalyser() {
org.apache.lucene.analysis.Analyzer analyser = null;
try {
analyser = CustomAnalyzer.builder()
.addCharFilter(HTMLStripCharFilterFactory.class)
.addCharFilter(MappingCharFilterFactory.class, getMappingSettings())
.withTokenizer(StandardTokenizerFactory.class)
.addTokenFilter(StandardFilterFactory.class)
.addTokenFilter(LowerCaseFilterFactory.class)
.addTokenFilter(SnowballPorterFilterFactory.class, getSnowballPorterSettings())
.addTokenFilter(SynonymFilterFactory.class, getSynonymSettings())
.addTokenFilter(ASCIIFoldingFilterFactory.class)
.addTokenFilter(PhoneticFilterFactory.class, getPhoneticSettings())
.addTokenFilter(StopFilterFactory.class, getStopSettings())
.build();
} catch (IOException ex) {
logger.info("[SearchConfig] [englishWordAnalyser] Failed to create components", ex);
}
return analyser;
}
protected StringField createStringField(String name, String value, LuceneOptions luceneOptions) {
final StringField field = new StringField(name, value, luceneOptions.getStore());
final Analyzer analyzer = SearchConfig.getEnglishWordAnalyser();
try {
final TokenStream tokenStream = analyzer.tokenStream(name, new StringReader(value));
tokenStream.reset();
field.setBoost(luceneOptions.getBoost());
field.setTokenStream(tokenStream);
field.setStringValue(value);
tokenStream.end();
tokenStream.close();
} catch (IOException e) {
e.printStackTrace();
}
analyzer.close();
return field;
}
从FieldBridge添加新字段:
createStringField("NAME", "VALUE", luceneOptions);
我还希望在创建如下多字段QueryParser时能够使用此分析器:
final QueryParser parser = new MultiFieldQueryParser(getClassLuceneFields(clazz), getEnglishWordAnalyser());
现在,我用MultiFieldQueryParser测试了分析仪,它似乎工作得很好,但当对现场桥接器进行索引时,它会因以下错误而失效:
java.lang.IllegalArgumentException: TokenStream fields must be indexed and tokenized
这是由setTokenStream上的createStringField引起的
有人有什么想法吗
我可能完全走错了方向,如果是的话,有没有人有适合我的用例的替代方案
干杯我很惊讶Lucene不是这样工作的。Lucene希望您在字段中使用未分析的值构建文档,并且在将文档放入索引时,它将负责分析文档 Hibernate Search负责设置正确的配置,以便Lucene知道每个字段使用哪个分析器。碰巧,对于标准的
@Field
字段(@Field(analyzer=…)
),这很容易配置,但对于字段桥中添加的字段则不容易配置
目前,最简单的解决方案是第三种:分析器鉴别器。这不是分析仪鉴别器的预期用途,但会起作用
基本上,你必须:
- 通常使用
定义分析仪@AnalyzerDef
- 创建一个analyzer鉴别器,将字段映射到相应的analyzer定义:
public class MyDiscriminator implements Discriminator { public String getAnalyzerDefinitionName(Object value, Object entity, String fieldName) { switch ( fieldName ) { case "foo": return "analyzerNameForFieldFoo"; case "bar": return "analyzerNameForFieldBar"; default: return null; // Use the default analyzer } } }
- 将鉴别器应用于您的实体:
@Indexed @Entity @AnalyzerDiscriminator(impl = MyDiscriminator.class) public class MyEntity { // ... }