Hibernate Search 5.0数值Lucene查询HSEARCH000233问题

亚当

问题:我们如何为休眠搜索提供包含数字和非数字字段的原始Lucene查询字符串?

背景:我们最近升级到了HibernateSearch 5.0,由于HibernateSearch查询解析器(pre-lucene)发生了以下错误,我们的许多查询现在都失败了:

The specified query contains a string based sub query which targets the numeric encoded field(s)

在大多数情况下,MultiFieldQueryParser由于我们正在运行的查询的复杂性,我们使用lucene的文本语法以及将传递查询到HibernateSearch中。直到HibernateSearch 5.0为止,它们都运行良好。在升级过程中,我们遇到了HibernateSearch抛出的异常,这些异常阻止了我们的应用程序运行正常的查询。我们不明白为什么会引发异常或前进的最佳方法。

在试图找出问题的过程中,我尝试以最原始的方式简化了哪些有效,哪些无效。(这是由HibernateSearch的QueryValidationTest构建的)。

例子:

给定以下Entity类:

@Entity
@Indexed
public static class B {
    @Id
    @GeneratedValue
    private long id;

    @Field
    private long value;

    @Field
    private String text;
}

测试1(我们如何为休眠搜索编写查询:失败):

        QueryParser parser = new MultiFieldQueryParser(new String[]{"id","value","num"},new StandardAnalyzer());
        Query query = parser.parse("+(value:1 text:test)");
        FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery( query, B.class );
        fullTextQuery.list();

结果是:

org.hibernate.search.exception.SearchException: HSEARCH000233: The specified query '+(value:1 text:test)' contains a string based sub query which targets the numeric encoded field(s) 'value'. Check your query or try limiting the targeted entities.
at org.hibernate.search.query.engine.impl.LazyQueryState.validateQuery(LazyQueryState.java:163)
at org.hibernate.search.query.engine.impl.LazyQueryState.search(LazyQueryState.java:102)
at org.hibernate.search.query.engine.impl.QueryHits.updateTopDocs(QueryHits.java:227)
at org.hibernate.search.query.engine.impl.QueryHits.<init>(QueryHits.java:122)
at org.hibernate.search.query.engine.impl.QueryHits.<init>(QueryHits.java:94)
at org.hibernate.search.query.engine.impl.HSQueryImpl.getQueryHits(HSQueryImpl.java:436)
at org.hibernate.search.query.engine.impl.HSQueryImpl.queryEntityInfos(HSQueryImpl.java:257)
at org.hibernate.search.query.hibernate.impl.FullTextQueryImpl.list(FullTextQueryImpl.java:200)
at org.hibernate.search.test.query.validation.QueryValidationTest.testRawLuceneWithNumericValue(QueryValidationTest.java:156)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.hibernate.testing.junit4.ExtendedFrameworkMethod.invokeExplosively(ExtendedFrameworkMethod.java:62)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.hibernate.testing.junit4.FailureExpectedHandler.evaluate(FailureExpectedHandler.java:58)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.hibernate.testing.junit4.BeforeClassCallbackHandler.evaluate(BeforeClassCallbackHandler.java:43)
at org.hibernate.testing.junit4.AfterClassCallbackHandler.evaluate(AfterClassCallbackHandler.java:42)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:264)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:124)
at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:200)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:153)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)

测试2 :(使用数字范围变化的失败方式相同:失败):

        QueryParser parser = new MultiFieldQueryParser(new String[]{"id","value","text"},new StandardAnalyzer());
        Query query = parser.parse("+(value:[1 TO 1] text:test)");
        FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery( query, B.class );
        fullTextQuery.list();

测试3 :(使用lucene术语:SUCCESS)

        TermQuery query = new TermQuery( new Term("text", "bar") );
    TermQuery nq = new TermQuery( new Term("value", "1") );

    BooleanQuery bq = new BooleanQuery();
    bq.add(query, Occur.SHOULD);
    bq.add(nq, Occur.SHOULD);

    FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery( bq, B.class );

注意:完整的测试用例版本可以在这里查看我们所看到的测试:https : //github.com/abrin/hibernate-search/blob/3fdcc8229f0bfa00329b9d977172fd218d82cac2/orm/src/test/java/org/hibernate /search/test/query/validation/QueryValidationTest.java

谢谢

哈代

首先,出现问题的原因是从Search 5开始,数字类型被索引为Lucene数字字段(与基于字符串的字段相对)。除了提高性能外,它还允许例如对数字字段进行排序而无需填充。Search 5文档说以下内容:

在搜索5之前,仅当通过@NumericField明确请求时才选择数字字段编码。从搜索5开始,将自动为数字类型选择此编码。为了避免数字编码,您可以通过@ Field.bridge或@FieldBridge显式指定非数字字段桥。包org.hibernate.search.bridge.builtin包含一组将数字编码为字符串的桥,例如org.hibernate.search.bridge.builtin.IntegerBridge。

因此,如果您要坚持原来的行为,则需要确保您的数值仍被索引为字符串。在您的示例中,value需要使用进行索引org.hibernate.search.bridge.builtin.LongBridge您可以通过@FieldBridge注释来实现这一点(您可以忽略id的大小写,因为文档ID始终以字符串形式索引):

@Field
@FieldBridge(impl = LongBridge.class)
private long value;

有关您的测试方案的一些评论:

  • Test1:查询解析器仅创建基于字符串的查询。Lucene不知道在此级别上对哪些字段进行了数字索引。只能使用适当的来定位/搜索数字字段NumericRangeQuery如果仍然要使用查询解析器,则需要提供自己的子类并自己处理数字字段。另请参见-如何使Lucene中的QueryParser处理数字范围?
  • 测试2:同样的问题。即使您使用的是range语法value:[1 TO 1],它也只会创建文本/字符串范围查询。
  • 测试3:我认为这实际上不起作用。它可能不会引发异常,但是我很确定,如果您查看多个搜索结果,就会注意到该value术语被忽略了。ATermQuery是基于字符串的,将无法在数字编码字段中找到匹配项。另请参阅Lucene 3.0.3数值词查询

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章