-->
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.  [ 13 posts ] 
Author Message
 Post subject: Hibernate Search Custom FieldBridge TwoWayFieldBridge
PostPosted: Wed Nov 03, 2010 1:28 pm 
Beginner
Beginner

Joined: Wed Nov 03, 2010 1:05 pm
Posts: 24
Hi,

I'm new on this forum and on hibernate search.

I would like to develop a custom fieldBridge (TwoWayFieldBridge) for a composite key.

Here is the concerned entity:

Code:
@Entity
@Indexed(index="person")
@Table(name="PERSON")
public class Person extends VersionedObject implements Serializable, Cloneable{...}


The pk is stored inside "versionedObject" class defined as follow:
As you can see the pk is an object.
Code:
@MappedSuperclass
public abstract class VersionedObject implements Cloneable, Serializable {
  @Id
  private VersionKey pk;
  ...
  ...
}


Here is the VersionKey object:
So the pk is in fact devided into two elements id & version.

Code:
@Embeddable
public class VersionKey implements Serializable, Cloneable {

  @JoinColumn(name="V_NO")
  @ManyToOne(targetEntity=Version.class, fetch=FetchType.EAGER)
  private Version version;

  @Column(nullable=false)
  private Integer id;

  public VersionKey() {
    super();
  }


Here is the version object:

Code:
@Entity
@Table(name="VERSIONS")
public class Version implements Serializable {

  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  @Column(name="V_NO", length=10)
  private Integer valueNb;

  @Column(nullable=false)
  @Temporal(TemporalType.TIMESTAMP)
  private Date tstamp;

  @Column(length=UserProfile.CAID_LENGTH, nullable=false)
  private String userId;

  @Column(length=500)
  private String message;

  @CollectionOfElements
  @JoinTable(
      name="TAGS",
      joinColumns=@JoinColumn(name="V_NO")
      )
  @Column(name="LABEL", length=64)
  private Set<String> tags;


I would like to know how do I have to create the TwoWayFieldBridge.
Do I have to save in the index file each attribute from Version Entity + the id from VersionKey Entity and then sets all the attribute of the object... ?
like having the following class:

Code:
public class PkFieldBridge implements TwoWayFieldBridge {


  public Object get(String fieldName, Document doc) {
    VersionKey questionPK = new VersionKey();
    Field field = null;
    field = doc.getField(fieldName + ".id");
    questionPK.setId(new Integer(field.stringValue()));
    field = doc.getField(fieldName + ".valueNb");
    Version version = new Version();
   
   
    field = doc.getField(fieldName + ".message");
    version.setMessage(field.stringValue());
    field = doc.getField(fieldName + ".userId");
    version.setUserId(field.stringValue());
    field = doc.getField(fieldName + ".valueNb");
    version.setValueNb(Integer.parseInt(field.stringValue()));
    questionPK.setVersion(version);
    ....
    // set the date by getting all part of the date (day, month, hour,..) which is stored in the index???
   // or can i retrieve the object directly???
     ...

    return questionPK;
  }


Top
 Profile  
 
 Post subject: Re: Hibernate Search Custom FieldBridge TwoWayFieldBridge
PostPosted: Wed Nov 03, 2010 6:38 pm 
Hibernate Team
Hibernate Team

Joined: Fri Oct 05, 2007 4:47 pm
Posts: 2536
Location: Third rock from the Sun
Hi,
interesting question (and mapping).
Honestly I never saw such a case before, in theory I would have said that you have to restore all fields, but I assume Hibernate Core won't read the non-required fields needed to load the original entity from the database.
You should try it storing only the id and valueNb, I think it should work for normal full text queries returning managed entities, but it won't certainly work for projections; you might be fine with that, it depends on your use case.

To make it complete and safe you should store all fields, but this requires quite some coding and assuming you won't query on the other fields it will also make the index unnecessarily large.

_________________
Sanne
http://in.relation.to/


Top
 Profile  
 
 Post subject: Re: Hibernate Search Custom FieldBridge TwoWayFieldBridge
PostPosted: Thu Nov 04, 2010 5:17 am 
Beginner
Beginner

Joined: Wed Nov 03, 2010 1:05 pm
Posts: 24
Hi,

Thank you for your reply :-)
I've never seen that case before neither... but it's quiet interesting.
I'll try like you said: take the id and the valueNb, It should be enough in my case.
I need to display all persons list found by h.search.
Good remark! If projection is only searching data from the index without touching the db (make use of the index as database is that right?), I won't use that.

I think I'll also face other problems.
Actually(without hibernate search, only hibernate queries), to find this list of persons, the query that I use will also check if you got enough roles based on your userId.
Now that I'm going to use hibernate search, I will also have to go through filtering the resultSet and check the roles in the database in order to keep the security. Do you think it's possible? I don't have enough view on hibernate search possibilities.

Thanks for your help ;-)


Top
 Profile  
 
 Post subject: Re: Hibernate Search Custom FieldBridge TwoWayFieldBridge
PostPosted: Thu Nov 04, 2010 5:28 am 
Hibernate Team
Hibernate Team

Joined: Fri Oct 05, 2007 4:47 pm
Posts: 2536
Location: Third rock from the Sun
Quote:
Now that I'm going to use hibernate search, I will also have to go through filtering the resultSet and check the roles in the database in order to keep the security. Do you think it's possible? I don't have enough view on hibernate search possibilities.

yes it's possible, but you might want to see if applying the filters at Hibernate (core) level could be good enough.
In case of Search I'd not recommend to encode security metadata in the index: when groups are changed, all related metatada in related documents must be rewritten. Rather implement a custom bitset based filter, please see the unit tests for examples of implementing one.

_________________
Sanne
http://in.relation.to/


Top
 Profile  
 
 Post subject: Re: Hibernate Search Custom FieldBridge TwoWayFieldBridge
PostPosted: Thu Nov 04, 2010 10:00 am 
Beginner
Beginner

Joined: Wed Nov 03, 2010 1:05 pm
Posts: 24
that's perfect :-)

Last question maybe,
Actually I have the application searching for person entities from the database using basic hibernate.
This part I won't change it.
I just need hibernate search to implement a search functionality in the application.
Do I need to rewrite all the current basic hibernate queries used to populate the main table with person entities with hibernate search? Or can I just use hibernate search for the search functionality?


Last edited by abstractMan on Fri Nov 05, 2010 5:36 am, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Hibernate Search Custom FieldBridge TwoWayFieldBridge
PostPosted: Thu Nov 04, 2010 11:09 am 
Beginner
Beginner

Joined: Wed Nov 03, 2010 1:05 pm
Posts: 24
I know why I got all those extra record in my table.
The session is wrapped in the initIndex method and keep the new record from the index in the session...
It's just because I use this method in a wrong place but that's only for testing if I can retrieve something from the index.

But I'm always wondering if I can keep my original hibernate queries to populate this table and use only hibernate search only to find some records in the database based on a search pattern that find the searched token in the index and retrieve the founded element from the db.


When we do the query like in the above method initIndex, where does the info come from?
From the index? from the database? What is the process of the query?


Top
 Profile  
 
 Post subject: Re: Hibernate Search Custom FieldBridge TwoWayFieldBridge
PostPosted: Fri Nov 05, 2010 6:48 am 
Hibernate Team
Hibernate Team

Joined: Fri Oct 05, 2007 4:47 pm
Posts: 2536
Location: Third rock from the Sun
sure you can always continue to use Hibernate in all usual ways.
What Hibernate Search does (unless you use projections) is to identify the primary keys of entities which match your fulltext queries, but then the actual data is fetched from the database using efficient primary key loading. This guarantees the data you actually load is transactionally consistent with the rest of your database state even if you setup Hibernate Search to update the Lucene indexes in async mode.

Projections actually avoid any hit from the database, so it's recommended to use them only to speed up previews of resultsets.

_________________
Sanne
http://in.relation.to/


Top
 Profile  
 
 Post subject: Re: Hibernate Search Custom FieldBridge TwoWayFieldBridge
PostPosted: Fri Nov 05, 2010 8:33 am 
Beginner
Beginner

Joined: Wed Nov 03, 2010 1:05 pm
Posts: 24
Great :-) Thanks for your help


Top
 Profile  
 
 Post subject: Re: Hibernate Search Custom FieldBridge TwoWayFieldBridge
PostPosted: Tue Nov 09, 2010 5:11 am 
Beginner
Beginner

Joined: Wed Nov 03, 2010 1:05 pm
Posts: 24
I'm wondering if I need a twoWayFieldBridge or a twoWayStringBridge?


Top
 Profile  
 
 Post subject: Re: Hibernate Search Custom FieldBridge TwoWayFieldBridge
PostPosted: Tue Nov 09, 2010 6:07 am 
Beginner
Beginner

Joined: Wed Nov 03, 2010 1:05 pm
Posts: 24
I implemented the following twoWayStringBridge

Code:
public class TestFieldBridge implements TwoWayStringBridge {
 
  @Override
  public String objectToString(Object arg0) {
     
     String retString = null;
     
     if (arg0 instanceof VersionKey) {
       VersionKey id = (VersionKey)arg0;
        StringBuilder sb = new StringBuilder();
        retString = sb.append(id.getId()).append("_")
                    .append(id.getVersion().getValueNb()).append("_")
                    .append(id.getVersion().getMessage()).append("_")
                    .append(id.getVersion().getUserId()).append("_")
                    .append(String.valueOf(setTagSet(id.getVersion().getTags()))).append("_")
                    .append(String.valueOf(setTimeStamp(id.getVersion().getTstamp())))
                    .toString();
     }
     
     return retString;
  }

  @Override
  public Object stringToObject(String arg0) {
     
     String[] fields = arg0.split("_");
     
     VersionKey versionPK = new VersionKey();
     Version version = new Version();
     
     versionPK.setId(Integer.parseInt(fields[0]));
     
     version.setValueNb(Integer.parseInt(fields[1]));
     
     version.setMessage(fields[2]);
     
     version.setUserId(fields[3]);
     
     version.setTags(getTagSet(fields[4]));
     
     version.setTstamp(getTimeStamp(fields[5]));
     
     versionPK.setVersion(version);
     
     return versionPK;
  }
 
  private String setTagSet(Set<String>tag){
   
    if(tag == null)
      return "";
   
    StringBuilder negotiations = new StringBuilder("");
    final String token = "|";
   
   
    for (String currentTag : tag)
    {
        negotiations.append(currentTag);
        negotiations.append(token);
    }

    return negotiations.toString().trim();
  }
 
  private String setTimeStamp(Date date){
    return ""+date.getTime();
  }

  private Set<String> getTagSet(String tags){
   
    String[] tagTab = tags.split(":");
    Set<String> tagSet = new HashSet<String>();
   
    for (String currentTag : tagTab)
    {
        tagSet.add(currentTag);
    }
   
    return tagSet;
  }
 
  private Date getTimeStamp(String date){
    TimeZone GMT = TimeZone.getTimeZone("GMT");
    Calendar cal = GregorianCalendar.getInstance(GMT);
    cal.setTime(new Date(Long.parseLong(date)));
    return cal.getTime();
  }
}


In this case, as soon as I do an update on a person entity, I can see in the index that H.S delete one record in the index and create another one. That's perfect

But when I do a search, there is no result see code below: (as soon as there is one record deleted in the index, the search give me no results otherwise it works):

Code:
public List<T> luceneSearch(String searchPattern) throws DaoException {

    Session session = openSession();
   
    FullTextSession fullTextSession = Search.getFullTextSession(session);
    session.beginTransaction();
   
    org.apache.lucene.queryParser.QueryParser parser = new QueryParser("summary", new StandardAnalyzer() );

    try {
     
      org.apache.lucene.search.Query luceneQuery = parser.parse(searchPattern);
      org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery(luceneQuery);
     
      List <T> list = fullTextQuery.list(); //return a list of managed objects
      session.getTransaction().commit();
      return list;
    } catch (ParseException e) {
      logger.error(e);
      rollbackTransaction();
      throw new DaoException(e);
    }
   
  }


Last edited by abstractMan on Tue Nov 09, 2010 6:09 am, edited 2 times in total.

Top
 Profile  
 
 Post subject: Re: Hibernate Search Custom FieldBridge TwoWayFieldBridge
PostPosted: Tue Nov 09, 2010 6:07 am 
Beginner
Beginner

Joined: Wed Nov 03, 2010 1:05 pm
Posts: 24
Oups sorry for the double post... :s

I implemented the following twoWayStringBridge

Code:
public class TestFieldBridge implements TwoWayStringBridge {
 
  @Override
  public String objectToString(Object arg0) {
     
     String retString = null;
     
     if (arg0 instanceof VersionKey) {
       VersionKey id = (VersionKey)arg0;
        StringBuilder sb = new StringBuilder();
        retString = sb.append(id.getId()).append("_")
                    .append(id.getVersion().getValueNb()).append("_")
                    .append(id.getVersion().getMessage()).append("_")
                    .append(id.getVersion().getUserId()).append("_")
                    .append(String.valueOf(setTagSet(id.getVersion().getTags()))).append("_")
                    .append(String.valueOf(setTimeStamp(id.getVersion().getTstamp())))
                    .toString();
     }
     
     return retString;
  }

  @Override
  public Object stringToObject(String arg0) {
     
     String[] fields = arg0.split("_");
     
     VersionKey versionPK = new VersionKey();
     Version version = new Version();
     
     versionPK.setId(Integer.parseInt(fields[0]));
     
     version.setValueNb(Integer.parseInt(fields[1]));
     
     version.setMessage(fields[2]);
     
     version.setUserId(fields[3]);
     
     version.setTags(getTagSet(fields[4]));
     
     version.setTstamp(getTimeStamp(fields[5]));
     
     versionPK.setVersion(version);
     
     return versionPK;
  }
 
  private String setTagSet(Set<String>tag){
   
    if(tag == null)
      return "";
   
    StringBuilder negotiations = new StringBuilder("");
    final String token = "|";
   
   
    for (String currentTag : tag)
    {
        negotiations.append(currentTag);
        negotiations.append(token);
    }

    return negotiations.toString().trim();
  }
 
  private String setTimeStamp(Date date){
    return ""+date.getTime();
  }

  private Set<String> getTagSet(String tags){
   
    String[] tagTab = tags.split(":");
    Set<String> tagSet = new HashSet<String>();
   
    for (String currentTag : tagTab)
    {
        tagSet.add(currentTag);
    }
   
    return tagSet;
  }
 
  private Date getTimeStamp(String date){
    TimeZone GMT = TimeZone.getTimeZone("GMT");
    Calendar cal = GregorianCalendar.getInstance(GMT);
    cal.setTime(new Date(Long.parseLong(date)));
    return cal.getTime();
  }
}


In this case, as soon as I do an update on a person entity, I can see in the index that H.S delete one record in the index and create another one. That's perfect

But when I do a search, there is no result see code below: (as soon as there is one record deleted in the index, the search give me no results otherwise it works):

Code:
public List<T> luceneSearch(String searchPattern) throws DaoException {

    Session session = openSession();
   
    FullTextSession fullTextSession = Search.getFullTextSession(session);
    session.beginTransaction();
   
    org.apache.lucene.queryParser.QueryParser parser = new QueryParser("summary", new StandardAnalyzer() );

    try {
     
      org.apache.lucene.search.Query luceneQuery = parser.parse(searchPattern);
      org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery(luceneQuery);
     
      List <T> list = fullTextQuery.list(); //return a list of managed objects
      session.getTransaction().commit();
      return list;
    } catch (ParseException e) {
      logger.error(e);
      rollbackTransaction();
      throw new DaoException(e);
    }
   
  }


Top
 Profile  
 
 Post subject: Loader.load -> List result no object
PostPosted: Tue Nov 09, 2010 11:05 am 
Beginner
Beginner

Joined: Wed Nov 03, 2010 1:05 pm
Posts: 24
After investigating I can see that as soon as there is two element in my index, I got no result when I query the index.

But in debug mode I can see that the method List in the class FullTextQueryImpl got @ a certain moment the two element that stands in my index (the list infos got all the result) but once
Code:
List list = loader.load( infos.toArray( new EntityInfo[infos.size()] ) );
is executed, the List list is empty...
:

Code:
public List list() throws HibernateException {
      //find the directories
      IndexSearcher searcher = buildSearcher( searchFactoryImplementor );
      if ( searcher == null ) {
         return Collections.EMPTY_LIST;
      }
      try {
         QueryHits queryHits = getQueryHits( searcher, calculateTopDocsRetrievalSize() );
         int first = first();
         int max = max( first, queryHits.totalHits );

         int size = max - first + 1 < 0 ? 0 : max - first + 1;
         List<EntityInfo> infos = new ArrayList<EntityInfo>( size );
         DocumentExtractor extractor = new DocumentExtractor(
               queryHits, searchFactoryImplementor, indexProjection, idFieldNames, allowFieldSelectionInProjection
         );
         for ( int index = first; index <= max; index++ ) {
            infos.add( extractor.extract( index ) );
         }
         Loader loader = getLoader();
         List list = loader.load( infos.toArray( new EntityInfo[infos.size()] ) );
         if ( resultTransformer == null || loader instanceof ProjectionLoader ) {
            //stay consistent with transformTuple which can only be executed during a projection
            return list;
         }


Someone got any idea the reason why?


Top
 Profile  
 
 Post subject: Re: Hibernate Search Custom FieldBridge TwoWayFieldBridge
PostPosted: Wed Nov 10, 2010 3:25 am 
Beginner
Beginner

Joined: Wed Nov 03, 2010 1:05 pm
Posts: 24
Bug Hibernate search 3.1.1GA


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 13 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.