使用 FieldBridges 实施 Lucene 分析器
Implement Lucene analysers with FieldBridges
我想以与 FieldBridges 和手动搜索配合良好的方式实现 Lucene 分析器。理想情况下,我希望代码重复尽可能少。
我知道大多数教程都会告诉您使用@AnalyzerDef 注释初始化分析器,虽然我这样做并使一切正常,但我无法使在 FieldBridges 中创建的字段尊重分析器。 (使用 luceneoptions.addFieldToDocument 创建)。
我试图找到另一种方法来执行此操作,但文档很少。
这是我想出的 (为了使这个 post 简短一些代码已经被编辑,但如果需要我会 post 更多。) :
正在创建分析器:
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);
我也希望能够在像这样创建 MultiFieldQueryParser 时使用此分析器:
final QueryParser parser = new MultiFieldQueryParser(getClassLuceneFields(clazz), getEnglishWordAnalyser());
现在我用 MultiFieldQueryParser 测试了分析器,它似乎运行良好,但是当 FieldBridges 被索引时,它出现了这个错误:
java.lang.IllegalArgumentException: TokenStream fields must be indexed and tokenized
这是在 setTokenStream 的 createStringField 中引起的。
有没有人有什么想法?
我可能完全走错了方向,如果是这样,有没有人有任何替代方案也适合我的用例。
干杯
恐怕 Lucene 不是这样工作的。 Lucene 希望您在其字段中构建具有未分析值的文档,并且当您将它们放入索引时它会负责分析文档。
Hibernate Search 负责设置正确的配置,以便 Lucene 知道为每个字段使用哪个分析器。碰巧这对于标准 @Field
字段(@Field(analyzer = ...)
)来说很容易配置,但对于字段桥接中添加的字段则不然。
目前,最简单的解决方案是描述的第三个 in this blog post:分析器鉴别器。这不是分析器鉴别器的预期目的,但它会起作用。
基本上你必须:
- 像往常一样使用
@AnalyzerDef
定义分析器
创建一个分析器鉴别器,将您的字段映射到相应的分析器定义:
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 {
// ...
}
有关分析器鉴别器的更多文档,请参阅here。
我想以与 FieldBridges 和手动搜索配合良好的方式实现 Lucene 分析器。理想情况下,我希望代码重复尽可能少。
我知道大多数教程都会告诉您使用@AnalyzerDef 注释初始化分析器,虽然我这样做并使一切正常,但我无法使在 FieldBridges 中创建的字段尊重分析器。 (使用 luceneoptions.addFieldToDocument 创建)。
我试图找到另一种方法来执行此操作,但文档很少。
这是我想出的 (为了使这个 post 简短一些代码已经被编辑,但如果需要我会 post 更多。) :
正在创建分析器:
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);
我也希望能够在像这样创建 MultiFieldQueryParser 时使用此分析器:
final QueryParser parser = new MultiFieldQueryParser(getClassLuceneFields(clazz), getEnglishWordAnalyser());
现在我用 MultiFieldQueryParser 测试了分析器,它似乎运行良好,但是当 FieldBridges 被索引时,它出现了这个错误:
java.lang.IllegalArgumentException: TokenStream fields must be indexed and tokenized
这是在 setTokenStream 的 createStringField 中引起的。
有没有人有什么想法?
我可能完全走错了方向,如果是这样,有没有人有任何替代方案也适合我的用例。
干杯
恐怕 Lucene 不是这样工作的。 Lucene 希望您在其字段中构建具有未分析值的文档,并且当您将它们放入索引时它会负责分析文档。
Hibernate Search 负责设置正确的配置,以便 Lucene 知道为每个字段使用哪个分析器。碰巧这对于标准 @Field
字段(@Field(analyzer = ...)
)来说很容易配置,但对于字段桥接中添加的字段则不然。
目前,最简单的解决方案是描述的第三个 in this blog post:分析器鉴别器。这不是分析器鉴别器的预期目的,但它会起作用。
基本上你必须:
- 像往常一样使用
@AnalyzerDef
定义分析器 创建一个分析器鉴别器,将您的字段映射到相应的分析器定义:
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 { // ... }
有关分析器鉴别器的更多文档,请参阅here。