2012-02-08 30 views
3

MySQL's full text searchの機能を、ネイティブクエリを使用せずにJPAを使用して使いたいです。JPAからMySQLのフルテキスト検索を使用する方法

私はネイティブSQLコマンド:FUNCをサポートする機能を持つEclipseLinkを使用しています。ただし、ヘルプの例では、これが単純なMySQL関数でのみ使用されていることを示しています。次のようにMATCH & AGAINSTで動作するように得るために、私のベストエフォート型試みがある:私はFUNCメソッドを使用している他の選択肢に開いてい

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 

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

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

次の例外を与えます。

私はEJB 3とEclipseLink 2.3.1を使用しています。

+0

はあなたがcreateNativeQueryと試みたことがありますか? – perissf

答えて

4

FUNCのみ MATCH(ARG1、ARG2)、すなわち通常印刷機能、

で動作

ARG2戦のARG1は、機能が正常に印刷されている方法は印刷されないので、FUNCを呼び出すために使用することができませんそれ。

EclipseLink ExpressionOperatorsはこのような印刷機能をサポートしているため、独自のExpressionOperatorを定義できますが、ExpressionOperatorsはJPQLではなく、EclipseLink Expressionクエリでのみサポートされています。 JPQLでオペレータサポートを強化するためにログを記録することができます。

ネイティブSQLクエリを使用することもできます。

+1

あなたはこの回答の例を挙げることができますか、少し詳しく説明できます –

2

EclipseLink 4.0の新しいSQL演算子について教えてください。私はそれがJPQLから全文検索をするのに役立つと思います。しかし、EclipseLink 4.0にアップグレードする必要があります。

http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/Support_for_Native_Database_Functions#SQL

編集:
後半の更新のために申し訳ありません。 MySQLのフルテキスト検索とEclispeLink 2.4.0「SQL」演算子の
検証正しい使用はnameは、フルテキストインデックスが定義されているカラムである

SELECT person FROM People person WHERE SQL('MATCH(name) AGAINST(?)', :searchTerm)" 

あります。 :searchTermは、検索に使用する文字列です。
問題なく動作します。あなたがあなたのテーブルcolumsウィット指数

@NamedNativeQueryフルサーチ(名前= "searchclient" を設定している場合

+0

この場合、「new」演算子はどのように使用しますか? – Kevin

+0

私はこの「SQL」オペレータのユースケースを2-3日で自分自身で試してみるつもりはない。私が成功すれば私は正確な解決策で私の答えを編集します。私はそれが "FUNC"演算子のようなものに使用されるべきであるという考えを持っています: "SELECT person FROM people person WHERE SQL( 'MATCH(name)AGAINST(?)'、:searchTerm)" –

0

がついに

を働く、 クエリ=「クライアントSELECT * FROM WHERE MATCH(clientFullName、姓、secondname、 firstphone、」 + "secondphone、はworkPhone、otherphone、otherphone1、" + "otherphone2、detailsFromClient、電子メール、会社、" + "アドレス、contractType、paymantCondition)(AGAINST?)"、

一覧リスト= EM .createName dQuery( "searchclient")。setParameter(1、searchKey)。getResultList();

4

私は同じ問題を抱えていましたが、基準ビルダーを使用しました。 、EclipseLinkの表現

  • 使用するSQL方法
  • あなたは複合インデックスに対して一致した場合に

    1. キャストJPA式:これは、あなたがのEclipseLinkを使用している場合は、スタンダールの実装に制限を回避する方法であります関数法

    を使用して作成します。例:

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

    ジェームズの答えについて詳しく説明するには:

    私は運

    registerFunction("match", new SQLFunctionTemplate(DoubleType.INSTANCE,  "match(?1) against (?2 in boolean mode)")); 
    
    を使用してMySQLの方言を延長していたように思え

    、以下JPQL断片

    match(" + binaryDataColumn + ",'" + StringUtils.join(words, " ") + "') > 0 
    
    介して関数を呼び出します

    私は戻り値の型を推測しなければなりませんでしたが、これはあなたを起動させるはずです。

    4

    Hibernateで動作する@Markus Barthlenの改善された答え。

    は、カスタムの方言

    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; 
    

    または基準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

    0

    最も簡単なバリアントがにありますNativeQueryを使用

    JPAエンティティ(FiasAddress)へのマッピングで使用することの

    例:

    public class FiasServiceBean implements FiasService { 
    
        @PersistenceContext(unitName = "fias") 
        EntityManager entityManager; 
    
        @Override 
        public Collection<FiasAddress> search(String name, int limit, int aolevel) { 
         Query query = entityManager.createNativeQuery(
           "SELECT fa.* FROM fias.addressobject fa" + 
             " WHERE MATCH(FORMALNAME) AGAINST (:name IN NATURAL LANGUAGE MODE)" + 
             " AND AOLEVEL = :AOLEVEL" + 
             " LIMIT :limit", 
           FiasAddress.class 
         ); 
         query.setParameter("name", name); 
         query.setParameter("limit", limit); 
         query.setParameter("AOLEVEL", aolevel); 
         Iterator iterator = query.getResultList().iterator(); 
         ArrayList<FiasAddress> result = new ArrayList<>(); 
         while (iterator.hasNext()) { 
          result.add((FiasAddress) iterator.next()); 
         } 
         return result; 
        } 
    } 
    
    関連する問題