2012-04-19 20 views
8

? Estoy aprendiendo el Hibernate Search Query DSL, y no estoy seguro de cómo construir consultas usando argumentos booleanos como AND u OR.¿Cómo uso operadores booleanos con Hibernate Search

Por ejemplo, supongamos que quiero devolver todos los registros de personas que tienen un valor firstName de "factura" o "bob".

Siguiendo los docs de hibernación, un ejemplo utiliza el método bool() w/dos subconsultas, tales como:

QueryBuilder b = fts.getSearchFactory().buildQueryBuilder().forEntity(Person.class).get(); 
Query luceneQuery = b.bool() 
    .should(b.keyword().onField("firstName").matching("bill").createQuery()) 
    .should(b.keyword().onField("firstName").matching("bob").createQuery()) 
    .createQuery(); 

logger.debug("query 1:{}", luceneQuery.toString()); 

Esta última instancia produce la consulta lucene que quiero, pero esto es la forma correcta de utilizar lógica booleana con búsqueda de hibernación? ¿Es "should()" el ​​equivalente de "OR" (de manera similar, "must()" corresponde a "AND") ?.

Además, escribir una consulta de esta manera parece engorroso. Por ejemplo, ¿qué pasa si tengo una colección de firstNames con los que puedo comparar? ¿Es este tipo de consulta una buena coincidencia para el DSL en primer lugar?

+0

'' y 'must' es, pero' should' parece como una especie de versión más suave del ' y' Definitivamente no 'o'. En teoría, puede obtener 'o' como' no y no', obteniendo 'debe (b.must(). Not(). Debe(). Not()). Not()' pero esa no es una respuesta muy satisfactoria. – trutheality

Respuesta

3

Sí, su ejemplo es correcto. Los operadores booleanos se llaman deben en lugar de O debido a los nombres que tienen en la API y documentación de Lucene, y porque es más apropiado: no solo influye en una decisión booleana, sino que también afecta la puntuación del resultado .

Por ejemplo, si busca automóviles "de la marca Fiat" O "azul", los automóviles con la marca Fiat Y azul también serán devueltos y tendrán una puntuación más alta que los que sean azules pero no Fiat.

Puede ser engorroso porque es programático y ofrece muchas opciones detalladas. Una alternativa más simple es usar una cadena simple para su consulta y usar el QueryParser para crear la consulta. En general, el analizador es útil para analizar la entrada del usuario, el programático es más fácil de tratar con campos bien definidos; por ejemplo, si tiene la colección que mencionó, es fácil compilarla en un para el bucle.

1

Para contestar la pregunta secundaria:

Por ejemplo, lo que si tuviera una colección de firstNames a contrastar?

No soy un experto, pero según (el tercer ejemplo desde el final de) 5.1.2.1. consultas de palabras clave en Hibernate Search Documentation, que deben ser capaces de construir la consulta de este modo:

Collection<String> namesCollection = getNames(); // Contains "billy" and "bob", for example 
StringBuilder names = new StringBuilder(100); 
for(String name : namesCollection) { 
    names.append(name).append(" "); // Never mind the space at the end of the resulting string. 
} 

QueryBuilder b = fts.getSearchFactory().buildQueryBuilder().forEntity(Person.class).get(); 
Query luceneQuery = b.bool() 
    .should(
     // Searches for multiple possible values in the same field 
     b.keyword().onField("firstName").matching(sb.toString()).createQuery() 
    ) 
    .must(b.keyword().onField("lastName").matching("thornton").createQuery()) 
    .createQuery(); 

y, tiene como resultado, Person s con (firstNamepreferentemente "Billy" o "bob") Y (lastName = "thornton"), aunque no creo que le dé al bueno de Billy Bob Thornton un puntaje más alto ;-).

1

También puede usar BooleanQuery. Preferiría esto porque puedes usar esto en el ciclo de una lista.

org.hibernate.search.FullTextQuery hibque = null; 

    org.apache.lucene.search.BooleanQuery bquery = new BooleanQuery(); 

    QueryBuilder qb = fulltextsession.getSearchFactory().buildQueryBuilder() 
       .forEntity(entity.getClass()).get(); 
    for (String keyword : list) { 
     bquery.add(qb.keyword().wildcard().onField(entityColumn).matching(keyword) 
       .createQuery() , BooleanClause.Occur.SHOULD); 
    } 

    if (!filterColumn.equals("") && !filterValue.equals("")) { 
     bquery.add(qb.keyword().wildcard().onField(column).matching(value).createQuery() 
         , BooleanClause.Occur.MUST); 
    } 

    hibque = fulltextsession.createFullTextQuery(bquery, entity.getClass()); 

    int num = hibque.getResultSize(); 
1

Estaba buscando el mismo problema y tengo un problema algo diferente de lo presentado. Estaba buscando una unión real OR.El caso should no funcionó para mí, como resultados que no pasaron ninguna de las dos expresiones, pero con un puntaje más bajo. Quería omitir por completo estos resultados. Sin embargo, puede crear un booleano OR expresión real, utilizando una expresión booleana distinto en el que deshabilita Puntuación:

val booleanQuery = cb.bool(); 
val packSizeSubQuery = cb.bool(); 

packSizes.stream().map(packSize -> cb.phrase() 
    .onField(LUCENE_FIELD_PACK_SIZES) 
    .sentence(packSize.name()) 
    .createQuery()) 
    .forEach(packSizeSubQuery::should); 

booleanQuery.must(packSizeSubQuery.createQuery()).disableScoring(); 
fullTextEntityManager.createFullTextQuery(booleanQuery.createQuery(), Product.class) 
return persistenceQuery.getResultList(); 
+0

¿Sabes cómo comparar un valor con NULL en Hibernate Search? Por ejemplo, en SQL comparo un valor con NULL de esta manera: ** WHERE TABLE.FIELD IS NULL ** – adyjr

+0

¿No puede hacer una búsqueda por palabra clave con 'null' como valor? En lo que respecta a mi comprensión de Hibernate espacial, el puente de campo debe garantizar que su valor nulo se serialice por igual para la consulta, ya que se hace para almacenar la entidad, y esto debería funcionar de la caja. –

+0

Thks Jan. La respuesta está aquí: http://stackoverflow.com/a/11890368/2278773. Pero necesita usar la consulta nativa de Lucene. – adyjr

Cuestiones relacionadas