-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 
Author Message
 Post subject: custom operators (postgresql @@) in hql?
PostPosted: Thu Jun 10, 2010 3:46 pm 
Newbie

Joined: Sun Aug 28, 2005 1:29 pm
Posts: 12
I was wondering if it's possible to define/use a custom operator (in this case, the PostgreSQL @@ operator for full-text search) in HQL, without having to drop into a native SQL query. Using @@ in HQL directly fails, so I tried implementing SQLFunction and registering a function to provide the needed SQL. This also fails (when the query is parsed) because I don't want to use the function like this:

"... where f(x,y) = 1"

but like this

"... where f(x,y)"

where f(x,y) would get expanded to x @@ y

I don't see any way to do this in HQL, but I thought I'd check before using a native SQL query.

Thanks
Andrew


Top
 Profile  
 
 Post subject: Re: custom operators (postgresql @@) in hql?
PostPosted: Thu Jul 01, 2010 9:37 am 
Newbie

Joined: Sun Aug 28, 2005 1:29 pm
Posts: 12
I figured out how to do this from this post: viewtopic.php?f=1&t=944270&start=0

The key points are:
(A) recognize that SQLFunctions have to return a value and when used in HQL must be in an expression form (e.g., fts(body, 'dog') = true -- fts(body, 'dog') won't work in HQL)
(B) create a Hibernate SQLFunction for PG FTS; and
(C) remember that the expression "to_tsvector(body) @@ to_tsquery('dog')" evaluates to a boolean

(1) Create a new function class (e.g., PostgreSQLFullTextSearchFunction) which implements SQLFunction. The important method in this class is render().

Code:
package com.acme.hibernate;

import java.util.List;

import org.hibernate.QueryException;
import org.hibernate.dialect.function.SQLFunction;
import org.hibernate.engine.Mapping;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.type.BooleanType;
import org.hibernate.type.Type;

public class PostgreSQLFullTextSearchFunction implements SQLFunction {

   @SuppressWarnings("unchecked")
   public String render(List args, SessionFactoryImplementor factory) {
      if (args.size() != 3) {
         throw new IllegalArgumentException(
               "The function must be passed 3 arguments");
      }

      String ftsConfig = (String) args.get(0);
      String field = (String) args.get(1);
      String value = (String) args.get(2);

      String fragment = null;
      if (ftsConfig == null) {
         fragment = "to_tsvector(" + field + ") @@ " + "to_tsquery('"
               + value + "')";
      } else {
         fragment = "to_tsvector(" + ftsConfig + "::regconfig, " + field + ") @@ "
               + "to_tsquery(" + ftsConfig + ", " + value + ")";
      }
      return fragment;

   }

   @Override
   public Type getReturnType(Type columnType, Mapping mapping)
         throws QueryException {
      return new BooleanType();
   }

   @Override
   public boolean hasArguments() {
      return true;
   }

   @Override
   public boolean hasParenthesesIfNoArguments() {
      return false;
   }
}



(2) Create a new PostgreSQL Dialect class (e.g., MyPostgreSQLDialect), which extends PostgreSQLDialect, and in the constructor, register a *Hibernate* function that will get translated into the proper PostgreSQL syntax:

Code:
public class MyPostgreSQLDialect extends PostgreSQLDialect {
public MyPostgreSQLDialect() {
   registerFunction("fts", new PostgreSQLFullTextSearchFunction());
}
}


(3) Use the new Dialect in your Hibernate/JPA configuration settings. For example, for JPA, in META-INF/persistence.xml:
Code:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
             http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
   version="1.0">
   <persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
      <properties>
         <property name="hibernate.dialect"
            value="com.acme.hibernate.MyPostgreSQLDialect" />
...


(4) Use the Hibernate function just defined in code (assuming the Sentence class is an entity) in HQL:
Code:
...
List<Sentence> list = em.createQuery("select s from Sentence s where fts('english', s.body, :body) = true")
            .setParameter("body", "andrew").getResultList();
...


This generates a query like this:
Code:
select
        sentence0_.id as id0_,
        sentence0_.body as body0_
    from
        Sentence sentence0_
    where
        to_tsvector('english'::regconfig, sentence0_.body) @@ to_tsquery('english', ?)=true

which properly uses the FTS index.


Top
 Profile  
 
 Post subject: Re: custom operators (postgresql @@) in hql?
PostPosted: Sat Jul 30, 2011 8:25 am 
Newbie

Joined: Wed Jul 13, 2011 9:52 am
Posts: 2
Hi ageery,

it worked wonders for me thanks a lot,

i was trying to use the order by clause on the in the same hql query ,i found but the ordering of the results is by the custom fts query alone,

basically when i use fts() method in a hql query order by is not working.however wheni use the plain sql with tsquery and tsvector it works fine

any way to order the results based on the perticular column.?

thanks in advance...


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.