Как использовать полнотекстовый поиск MySQL из JPA

Я хочу использоватьПолнотекстовый поиск MySQL функции с использованием JPA, без необходимости использовать собственный запрос.

Я использую EclipseLink, который имеет функцию для поддержки собственных команд SQL:FUNC, Тем не менее, примеры помощи показывают только то, как это используется с простыми функциями MySQL. Моя лучшая попытка заставить его работать с MATCH & AGAINST заключается в следующем:

@PersistenceContext(name="test")
EntityManager em;

Query query = em.createQuery("SELECT person FROM People person WHERE FUNC('MATCH', person.name) FUNC('AGAINST', :searchTerm)");
...
query.getResultList();

Что дает следующее исключение:

Caused by: NoViableAltException([email protected][()* loopback of 822:9: (m= MULTIPLY right= arithmeticFactor | d= DIVIDE right= arithmeticFactor )*])
    at org.eclipse.persistence.internal.libraries.antlr.runtime.DFA.noViableAlt(DFA.java:159)
    at org.eclipse.persistence.internal.libraries.antlr.runtime.DFA.predict(DFA.java:116)
    at org.eclipse.persistence.internal.jpa.parsing.jpql.antlr.JPQLParser.arithmeticTerm(JPQLParser.java:4557)
    ... 120 more

Я открыт для альтернатив, кроме использования метода FUNC.

Я использую EJB 3 и EclipseLink 2.3.1.

 perissf08 февр. 2012 г., 12:03
Вы пробовали с createNativeQuery?

Ответы на вопрос(3)

который работает для Hibernate.

Создать собственный диалект
public class MySQLDialectCustom extends MySQL5Dialect {
  public MySQLDialect() {
    super();
    registerFunction("match", new SQLFunctionTemplate(StandardBasicTypes.DOUBLE,
        "match(?1) against  (?2 in boolean mode)"));
  }
}

и зарегистрируйте его, установивhibernate.dialect свойство.

Используй это

в JPQL:

Query query = entityManager
    .createQuery("select an from Animal an " +
             "where an.type = :animalTypeNo " +
             "and match(an.name, :animalName) > 0", Animal.class)
    .setParameter("animalType", "Mammal")
    .setParameter("animalName", "Tiger");
List<Animal> result = query.getResultList();
return result;

или с помощью Criteria API:

CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Animal> criteriaQuery = criteriaBuilder.createQuery(Animal.class);
Root<Animal> root = criteriaQuery.from(Animal.class);

List<Predicate> predicates = new ArrayList<>();

Expression<Double> match = criteriaBuilder.function("match", Double.class, root.get("name"),
criteriaBuilder.parameter(String.class, "animalName"));

predicates.add(criteriaBuilder.equal(root.get("animalType"), "Mammal"));
predicates.add(criteriaBuilder.greaterThan(match, 0.));

criteriaQuery.where(predicates.toArray(new Predicate[]{}));

TypedQuery<Animal> query = entityManager.createQuery(criteriaQuery);
List<Animal> result = query.setParameter("animalName", "Tiger").getResultList();

return result;

Еще некоторые подробности в этом блоге:http://pavelmakhov.com/2016/09/jpa-custom-function

у меня была та же проблема, но с использованием построителя критериев. Вот как вы можете обойти ограничения в стандартной реализации, если вы используете EclipseLink:

Привести выражение JPA к выражению EclipseLinkИспользуйте метод sqlЕсли вы сопоставляете с составным индексом, создайте его с помощью метода функции

Пример:

    JpaCriteriaBuilder cb = (JpaCriteriaBuilder) cb;

    List<String> args = new ArrayList();
    args.add("Keyword");

    Expression<Boolean> expr = cb.fromExpression (
      cb.toExpression(
         cb.function("", String.class,
           table.get(Table_.text1), table.get(Table_.text2)) 
      )                          
       .sql("MATCH ? AGAINST (?)", args)
     );

    query.where(expr);

Если вам нужно привести выражение к предикату, используйте следующее:

query.where( cb.gt(expr, 0));
Решение Вопроса

то есть МАТЧ (arg1, arg2)

Поскольку MATCH arg1 ПРОТИВ arg2 не печатается так, как обычно печатается функция, FUNC не может быть использована для ее вызова.

EclipseLink ExpressionOperators поддерживают такие функции печати, что вы можете определить свой собственный ExpressionOperator, но ExpressionOperators в настоящее время поддерживаются только через запросы EclipseLink Expression, но не через JPQL. Вы можете зарегистрировать расширение, чтобы иметь поддержку оператора в JPQL.

Вы также можете использовать собственный запрос SQL.

 Anil Sharma10 мая 2012 г., 22:06
Можете ли вы привести какой-либо пример этого ответа или можете немного уточнить

Ваш ответ на вопрос