Search code examples
javalucenehibernate-search

Hibernate-search search by list of numbers


I am working in a Hibernate-search, Java application with an entity which has a numeric field indexed:

@Field
@NumericField
private Long orgId;

I want to get the list of entities which match with a list of Long values for this property. I used the "simpleQueryString" because it allows to use "OR" logic with char | for several objective values. I have something like this:

queryBuilder.simpleQueryString().onField("orgId").matching("1|3|8").createQuery()

After run mi application I get:

The specified query '+(orgId:1 orgId:3 orgId:8)' contains a string based sub query which targets the numeric encoded field(s) 'orgId'. Check your query or try limiting the targeted entities.

So, Can some body tell me what is wrong with this code?, Is there other way to do what I need?.

================================= UPDATE 1:

yrodiere' answer solves the issue, but I have another doubt, I want validate whether entities match other fields, I know I can use BooleanJuntion, but then I need mix "must" and "should" usages right?. i.e.:

BooleanJunction<?> bool = queryBuilder.bool();
for (Integer orgId: orgIds) {
   bool.should( queryBuilder.keyword().onField("orgId").matching(orgId).createQuery() );
}
bool.must(queryBuilder.keyword().onField("name").matching("anyName").createQuery() );

Then, I am validating that the entities must match a "name" and also they match one of the given orgIds, Am I right?


Solution

  • As the error message says:

    The specified query [...] contains a string based sub query which targets the numeric encoded field(s) 'orgId'.

    simpleQueryString can only be used to target text fields. Numeric fields are not supported.

    If your string was generated programmatically, and you have a list of integers, this is what you'll need to do:

    List<Integer> orgIds = Arrays.asList(1, 3, 8);
    
    BooleanJunction<?> bool = queryBuilder.bool();
    for (Integer orgId: orgIds) {
       bool.should( queryBuilder.keyword().onField("orgId").matching(orgId).createQuery() );
    }
    LuceneQuery query = bool.createQuery();
    

    query will match documents whose orgId field contains 1, 3 OR 8.

    See https://docs.jboss.org/hibernate/search/5.11/reference/en-US/html_single/#_combining_queries

    EDIT: If you need additional clauses, I'd recommend not mixing must and should in the same boolean junction, but nesting boolean junctions instead.

    For example:

    BooleanJunction<?> boolForOrgIds = queryBuilder.bool();
    for (Integer orgId: orgIds) {
       boolForOrgIds.should(queryBuilder.keyword().onField("orgId").matching(orgId).createQuery());
    }
    
    
    BooleanJunction<?> boolForWholeQuery = queryBuilder.bool();
    boolForWholeQuery.must(boolForOrgIds.createQuery());
    boolForWholeQuery.must(queryBuilder.keyword().onField("name").matching("anyName").createQuery());
    // and add as many "must" as you need
    LuceneQuery query = boolForWholeQuery.createQuery();
    

    Technically you can mix 'must' and 'should', but the effect won't be what you expect: 'should' clauses will become optional and will only raise the score of documents when they match. So, not what you need here.