es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Buscar por lista de palabras clave

Tengo un problema con CriteriaBuilder.
Hay dos clases

public class Filter {
    Integer id;
    List<string> keyWords;
}

public class Entity {
    String name;
    String description;
}

Quiero obtener filtros que coincidan con Entity.
Imaginemos que tenemos una entidad (name = “abc”, description = “test description asd”)

Y filtros:
1. id = 1, keyWords = [“java”, “javascript”]
2. id = 2, keyWords = [“test”, “java”]

Se espera que se devuelva el filtro 2 porque la descripción (“test description asd”) contiene la palabra “test”.

CriteriaBuilder cb = new EntityManager().getCriteriaBuilder();
CriteriaQuery<filter> criteriaQuery = cb.createQuery(Filter.class);
Root<filter> root = criteriaQuery.from(Filter.class);
Predicate predicate = cb.like(root.get("keyWords").as(String.class), entity.getDescription());
CriteriaQuery<filter> cq = criteriaQuery.select(root).where(predicate);

Esta consulta devuelve un resultado vacío, pero funciona si se cambia “test description asd” a “test” o “java”…
Es posible dividir el campo de descripción por espacios y agregar muchos predicados, pero en mi opinión ese no es el enfoque correcto. El campo de descripción podría contener muchas palabras.

He intentado diferentes enfoques, pero no he encontrado una solución. ¿Podría alguien ayudar?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Como experto en tecnología de la información especializado en Java, Eclipselink y Criteria-API, hay varias posibles soluciones a este problema.

    Una posible solución es utilizar el método in() del CriteriaBuilder en lugar de like(). Esto permitiría verificar la lista de palabras clave en el campo de descripción. El código actualizado se vería así:

    CriteriaBuilder cb = new EntityManager().getCriteriaBuilder();
    CriteriaQuery<filter> criteriaQuery = cb.createQuery(Filter.class);
    Root<filter> root = criteriaQuery.from(Filter.class);
    
    // Crear una Expression que representa la descripción de la entidad dividida por espacios
    Expression<string> entityDescriptionExpression = cb
        .function("regexp_split_to_table", String.class, 
                  cb.literal(entity.getDescription()), 
                  cb.literal("\\s+")
        );
    
    // Crear un predicado que coincida con cualquiera de las palabras clave del filtro con la descripción de la entidad
    Predicate predicate = root
        .get("keyWords")
        .in(entityDescriptionExpression);
    
    CriteriaQuery<filter> cq = criteriaQuery
        .select(root)
        .where(predicate);
    
    List<filter> result = entityManager.createQuery(cq).getResultList();
    

    Este enfoque utiliza una función específica de PostgreSQL llamada regexp_split_to_table para dividir la descripción de la entidad por espacios y luego se comprueba si los resultados coinciden con las palabras clave del filtro utilizando el método in().

    Otra posible solución es utilizar el método like() del CriteriaBuilder con un carácter comodín. En este caso, el método like() verificaría si alguna de las palabras clave del filtro coincide con alguna parte de la descripción de la entidad. El código actualizado se vería así:

    CriteriaBuilder cb = new EntityManager().getCriteriaBuilder();
    CriteriaQuery<filter> criteriaQuery = cb.createQuery(Filter.class);
    Root<filter> root = criteriaQuery.from(Filter.class);
    
    // Unir las palabras clave en un solo string separado por el carácter comodín '%'
    String keywords = String.join("%", entity.getKeyWords()) + "%";
    
    // Crear un predicado que coincida una parte de la descripción de la entidad con las palabras clave del filtro
    Predicate predicate = cb.like(root.<string>get("description"), "%" + keywords + "%");
    
    CriteriaQuery<filter> cq = criteriaQuery
        .select(root)
        .where(predicate);
    
    List<filter> result = entityManager.createQuery(cq).getResultList();
    

    Este enfoque crea un string comodín mediante la unión de las palabras clave con el carácter ‘%’, y luego verifica si alguna parte de la descripción de la entidad coincide con este string comodín utilizando el método like().

    Cualquiera de estas soluciones debería proporcionar una forma de hacer coincidir los filtros con las entidades en función del campo de descripción.

Comments are closed.