elasticsearch,lucene,hibernate-search,Java,elasticsearch,Lucene,Hibernate Search" /> elasticsearch,lucene,hibernate-search,Java,elasticsearch,Lucene,Hibernate Search" />

Java 在构建针对多个实体运行的通用Lucene查询时,如何排除或忽略字段

Java 在构建针对多个实体运行的通用Lucene查询时,如何排除或忽略字段,java,elasticsearch,lucene,hibernate-search,Java,elasticsearch,Lucene,Hibernate Search,我们正在将java应用程序从使用SOLR/Lucene转换为Elasticsearch 5.6.6 在一个特定的区域中,我们以前会构建1个Lucene Search BooleanQuery,并对3个不同的实体运行它,寻找匹配项。在您运行实际查询之前,我们不需要指定它所针对的实体 BooleanQuery luceneQuery = myQueryBuilder.buildMyQuery(); session.createFullTextQuery(luceneQuery, entityOn

我们正在将java应用程序从使用SOLR/Lucene转换为Elasticsearch 5.6.6

在一个特定的区域中,我们以前会构建1个Lucene Search BooleanQuery,并对3个不同的实体运行它,寻找匹配项。在您运行实际查询之前,我们不需要指定它所针对的实体

 BooleanQuery luceneQuery = myQueryBuilder.buildMyQuery();
 session.createFullTextQuery(luceneQuery, entityOne);
 session.createFullTextQuery(luceneQuery, entityTwo);
 session.createFullTextQuery(luceneQuery, entityThree);
上面[luceneQuery]中的一个子查询在taxId上搜索,entityOne没有(没有taxId索引字段),但其他两个实体有。然而,它工作得很好,没有给出任何例外,我相信它只是忽略了未知/未索引字段,不完全确定它是如何工作的,但它确实做到了

现在我们转换到Elasticsearch DSL,我们需要预先给出实体,因此我(无论好坏)针对每个实体构建3次不同的查询,如下所示:

 QueryBuilder entityOneQB = session.getSearchFactory().buildQueryBuilder().forEntity(EntityOne.class).get();
 QueryBuilder entityTwoQB = session.getSearchFactory().buildQueryBuilder().forEntity(EntityTwo.class).get();
 QueryBuilder entityThreeQB = session.getSearchFactory().buildQueryBuilder().forEntity(EntityThree.class).get();
 // Create 3 exact (except for which entity they point at) queries
 Query entityOneQuery = myQueryBuilder.buildMyQuery(entityOne);
 Query entityTwoQuery = myQueryBuilder.buildMyQuery(entityTwo);
 Query entityThreeQuery = myQueryBuilder.buildMyQuery(entityThree);
其中buildMyQuery()有许多子查询,但处理taxId的子查询如下所示:

 qb.bool().should(
       qb.keyword()
         .onField("taxId")
         .matching(taxId)
         .createQuery()
    );
但是,现在,由于entityOne没有将taxId作为索引列/字段,因此
createQuery()
引发异常:

 SearchException: Unable to find field taxId in EntityOne
我的问题是:

  • 如果实体没有字段,有没有办法告诉Lucene忽略该字段

  • 如果没有,是否有某种方法,使用传入的QueryBuilder来确定实体是什么,这样,在taxId子查询代码中,我基本上可以说
    If(entityType==EntityOne){return null;}
    ,这样这个特定的子查询就不会包含在整个查询中了

  • 如果实体没有字段,有没有办法告诉Lucene忽略该字段

    只是澄清一下:是Hibernate搜索实现了DSL并抛出异常,而不是Lucene。Lucene是底层技术,不会执行太多验证

    如果您的目标是在一个结果列表中检索所有三个实体,并且如果在不同实体类型中具有相同名称的字段配置类似(例如,字段“名称”出现在实体1和2中,但具有相同的分析器),则您只需构建一个查询并在该查询中检索所有三种类型。你必须:

    • 确保在构建单个Lucene查询时,始终使用实体类型的查询生成器来实际定义目标字段:例如,如果目标为
      taxId
      ,则可以将查询生成器用于
      EntityTwo
      EntityThree
      ,但不能使用
      EntityOne
      的查询生成器。是的,没错:您可以在一个查询中混合使用多个查询生成器,只要在所有目标实体中以类似方式配置具有相同名称的字段
    • 以这种方式构建
      FullTextQuery
      :session.createFullTextQuery(luceneQuery,EntityOne.class,EntityTwo.class,EntityThree.class)
    如果没有,是否有某种方法,使用传入的QueryBuilder来确定实体是什么,这样,在taxId子查询代码中,我基本上可以说If(entityType==EntityOne){return null;},这样这个特定的子查询就不会包含在整个查询中


    不,没有。您可以通过向方法中添加一个参数来传递实体类型,不过:
    buildMyQuery(类类型,QueryBuilder-QueryBuilder)
    而不是
    buildMyQuery(QueryBuilder-QueryBuilder)

    只是为了澄清,我知道您正在使用Solr将应用程序迁移到Hibernate Search+Elasticsearch,而不使用Hibernate Search。如果情况并非如此,并且您一直在使用Hibernate搜索,那么请提供您过去和现在使用的Hibernate搜索版本。Eureka!我想知道为什么在构建QueryBuilder时以及在createFullTextQuery中都需要声明实体。我从来没有想到,可以基于1个实体构建querybuilder,然后基于另一个实体运行实际查询。我完全按照您在第一个要点中所说的做了(使用entityTwo构建查询,然后对所有3个实体运行查询),Hibernate Search再次感到高兴。很高兴它成功了。但是请注意,只有EntityTwo声明了您将在查询中提到的所有字段时,这才起作用。如果EntityOne声明字段“FieldOnlyEntityOne”,那么最终将出现完全相同的问题,并且必须使用EntityOne的查询生成器对该字段进行查询,再加上EntityTwo的查询生成器对其他字段进行查询。