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



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

在1个特定的领域中,我们之前会构建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索引字段(,但其他2个实体有。然而,它一切都很好,没有任何例外,我相信它只是忽略了未知/未索引的字段,不确定它是如何工作的,但它确实做到了。

现在我们正在转换到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

我的问题是:

  1. 如果实体没有字段,有没有办法告诉Lucene忽略它?

  2. 如果没有,有没有办法,使用传入的QueryBuilder来确定实体是什么,这样,在taxId子查询代码中,我基本上可以说if (entityType == EntityOne) {return null;},这样这个特定的子查询就不会包括在整个查询中?

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

只是一个澄清:实现DSL并抛出异常的是Hibernate Search,而不是Lucene。Lucene是底层技术,不进行太多验证。

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

  • 在构建单个Lucene查询时,请确保始终使用实体类型的查询生成器,该实体类型实际定义了您的目标字段:例如,如果目标为taxId,则可以将查询生成器用于EntityTwoEntityThree,但不能使用用于EntityOne的查询生成器。是的,没错:您可以在一个查询中混合使用多个查询生成器,只要在所有目标实体中具有相同名称的字段配置相似即可
  • 以这种方式构建FullTextQuerysession.createFullTextQuery(luceneQuery, EntityOne.class, EntityTwo.class, EntityThree.class);

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

不,没有。您可以向方法传递add参数以传递实体类型,不过:buildMyQuery(Class<?> type, QueryBuilder queryBuilder)而不是buildMyQuery(QueryBuilder queryBuilder)

最新更新