0
votes

We're in the process of converting our java application from using SOLR/Lucene to Elasticsearch 5.6.6.

In 1 particular area, we would previously build 1 Lucene Search BooleanQuery and run it against 3 different entities, looking for matches. We didn't need to specify the entity it would be used against until you ran the actual query.

 BooleanQuery luceneQuery = myQueryBuilder.buildMyQuery();
 session.createFullTextQuery(luceneQuery, entityOne);
 session.createFullTextQuery(luceneQuery, entityTwo);
 session.createFullTextQuery(luceneQuery, entityThree);

One sub-query within [luceneQuery] above searched on taxId, which entityOne doesn't have (no taxId indexed field) but the other 2 entities do have. However it all worked fine, no exceptions were given, I believe it just ignored the unknown/un-indexed field, not exactly sure how it worked, but it did.

Now we're converting over to Elasticsearch DSL, we need to give the entity up front so I (for better or worse) build the query 3 different times, against each entity, like so:

 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);

Where buildMyQuery() has a number of sub-queries but the one dealing with taxId looks something like:

 qb.bool().should(
       qb.keyword()
         .onField("taxId")
         .matching(taxId)
         .createQuery()
    );

However, now, since, entityOne doesn't have taxId as an indexed column/field, createQuery() throws an exception:

 SearchException: Unable to find field taxId in EntityOne

My questions are:

  1. Is there some way to tell Lucene to ignore the field if the entity doesn't have it?

  2. If not, is there some way, using the passed in QueryBuilder to determine what the entity is, so that, within the taxId subquery code, I can basically say if (entityType == EntityOne) {return null;} so that this particular sub-query won't be included in the overall query?

1

1 Answers

1
votes

Is there some way to tell Lucene to ignore the field if the entity doesn't have it?

Just a clarification: it's Hibernate Search that implements the DSL and throws exceptions, not Lucene. Lucene is the underlying technology, and doesn't perform much validation.

If your goal is to retrieve all three entities in a single result list, and if fields with the same name in different entity types are configured similarly (e.g. field "name" appears in entity 1 and 2, but has the same analyzer), you could simply build a single query and retrieve all three types in that single query. You will have to:

  • Make sure, when building the single Lucene query, to always use the query builder of an entity type that actually defines the field your targeting: if targeting taxId for instance, you can use the query builder for EntityTwo or for EntityThree, but not the one for EntityOne. Yes, that's right: you can mix multiple query builders in a single query, as long as fields with the same name are configured similarly in all targeted entities.
  • build the FullTextQuery that way: session.createFullTextQuery(luceneQuery, EntityOne.class, EntityTwo.class, EntityThree.class);.

If not, is there some way, using the passed in QueryBuilder to determine what the entity is, so that, within the taxId subquery code, I can basically say if (entityType == EntityOne) {return null;} so that this particular sub-query won't be included in the overall query?

No, there is not. You could pass add a parameter to your method to pass the entity type, though: buildMyQuery(Class<?> type, QueryBuilder queryBuilder) instead of buildMyQuery(QueryBuilder queryBuilder).