使用FieldBridges实现Lucene分析器

时间:2017-04-06 22:03:55

标签: lucene hibernate-search

我希望以与FieldBridges和手动搜索一致的方式实现lucene分析器。理想情况下,我希望尽可能少的代码重复。

我知道大多数教程都会告诉您使用@AnalyzerDef注释初始化您的分析器,虽然我这样做并且一切正常,但我无法在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;
    }

从FieldBridge添加新字段:

createStringField("NAME", "VALUE", luceneOptions);

我还希望能够在创建这样的MultiFieldQueryParser时使用此Analyzer:

    final QueryParser parser = new MultiFieldQueryParser(getClassLuceneFields(clazz), getEnglishWordAnalyser());

现在我使用MultiFieldQueryParser对分析器进行了测试,它似乎运行良好,但是当FieldBridges被编入索引时,它会出现这个错误:

java.lang.IllegalArgumentException: TokenStream fields must be indexed and tokenized

这是在setTokenStream的createStringField中引起的。

有没有人有任何想法?

我可能完全走向错误的方向,如果有的话,是否有人有任何替代方案也适合我的用例。

干杯

1 个答案:

答案 0 :(得分:1)

我很担心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