5 Replies Latest reply on Jul 10, 2015 8:59 AM by smoers

    Search on Date Field JodaTime

    smoers

      I use a data type "DateTime" of Jodatime package in my class "Author".

      To convert this data type to a lucene document, I use a class JodaTimeSplitBridge which implement the interface "TwoWayFieldBridge".

       

      If I search an object on the value of date field, It not found object !

       

      Author.java

      @Field(store=Store.YES, index=Index.YES)
      @FieldBridge(impl=JodaTimeSplitBridge.class)
      private DateTime creationdate;
      

       

      JodaTimeSplitBridge.java

      package org.infinispan;
      
      
      import org.apache.lucene.document.Document;
      import org.apache.lucene.index.IndexableField;
      import org.hibernate.search.bridge.LuceneOptions;
      import org.hibernate.search.bridge.TwoWayFieldBridge;
      import org.joda.time.DateTime;
      import org.joda.time.format.DateTimeFormat;
      
      
      
      
      public class JodaTimeSplitBridge implements TwoWayFieldBridge {
      
      
        @Override
        public void set(String name, Object value, Document document, LuceneOptions luceneoptions) {
      
      
        DateTime datetime = (DateTime) value;
        int year = datetime.getYear();
        int month = datetime.getMonthOfYear();
        int day = datetime.getDayOfMonth();
      
      
      
        // set year
        luceneoptions.addFieldToDocument(name+".year",String.valueOf(year), document);
      
        // set month
        luceneoptions.addFieldToDocument(name+".month", String.format("%02d",month), document);
      
      
        // set day
        luceneoptions.addFieldToDocument(name+".day", String.format("%02d",day), document);
      
        }
      
      
        @Override
        public Object get(String name, Document document) {
      
        IndexableField fieldyear = document.getField(name+".year");
        IndexableField fieldmonth = document.getField(name+".month");
        IndexableField fieldday = document.getField(name+".day");
        String strdate = fieldday.stringValue()+"/"+fieldmonth.stringValue()+"/"+fieldyear.stringValue();
        DateTime value = DateTime.parse(strdate, DateTimeFormat.forPattern("dd/MM/yyyy"));
        return String.valueOf(value);
        }
      
      
        @Override
        public String objectToString(Object date) {
      
        DateTime datetime = (DateTime) date;
        int year = datetime.getYear();
        int month = datetime.getMonthOfYear();
        int day = datetime.getDayOfMonth();
        String value = String.format("%02d",day)+"/"+String.format("%02d",month)+"/"+String.valueOf(year);
      
        return String.valueOf(value);
        }
      }
      
        • 1. Re: Search on Date Field JodaTime
          epbernard

          Can you show the query you are running?

          • 2. Re: Search on Date Field JodaTime
            smoers

            I'm sorry, I forgotten !

             

            QueryBuilder qb = sm.buildQueryBuilderForClass(AuthorInfinispan.class).get();
            Query q = qb.keyword().wildcard().onField("creationdate").matching(new DateTime()).createQuery();
            System.out.println(q.toString());
            CacheQuery cq = sm.getQuery(q, AuthorInfinispan.class);
            System.out.println(cq.getResultSize());
            • 3. Re: Search on Date Field JodaTime
              epbernard

              OK so that's a bit complicated and I can see why you expected this to work.

              Unfortunately today, Hibernate Search cannot know that you have created these specific subfields and how. Thus it can't create the query you expect on the three fields. We have plans for a future version of Hibernate Search to know how to do what (with a bit of extra metadata) but that's the future.

               

              There are two solutions really

               

              1. Use a single field

               

              Use the custom bridge but instead of creating three fields (for year, month, day), instead keep it as a single field in the form of yyyymmdd. If you do that, your query should be good to go.

               

              2. Change the query to take the three fields into account

               

              This one is more complicated but in essence, we need to directly query each three fields (and do the nice job that Hibernate Search Query DSL does otherwise.

               

              It would look something like that.

               

              int year = datetime.getYear(); 

              int month = datetime.getMonthOfYear(); 

              int day = datetime.getDayOfMonth();

               

              QueryBuilder qb = sm.buildQueryBuilderForClass(AuthorInfinispan.class).get();

              Query q = qb.bool()

                  .must( qb.keyword().onField("creationdate.year").ignoreFieldBridge().ignoreAnalyzer().matching(year).createQuery() )

                  .must( qb.keyword().onField("creationdate.month").ignoreFieldBridge().ignoreAnalyzer().matching(month).createQuery() )

                  .must( qb.keyword().onField("creationdate.day").ignoreFieldBridge().ignoreAnalyzer().matching(day).createQuery() )

                 .createQuery();

               

              CacheQuery cq = sm.getQuery(q, AuthorInfinispan.class);

              System.out.println(cq.getResultSize());

              • 4. Re: Search on Date Field JodaTime
                sannegrinovero

                Like Emmanuel I would suggest to encode the value in a single field name.

                On top of the "string friendly" format of yyyymmdd

                you can also use the Lucene numeric format, which is more efficient to run range queries; we have an example of such a TwoWayFieldBridge here:

                hibernate-search/NumericEncodingDateBridge.java at c06e4fe5fbc6b5a09195f40d760a093691f2c7f2 · hibernate/hibernate-search…

                • 5. Re: Search on Date Field JodaTime
                  smoers

                  Thank you both very much.

                   

                  It's working correctly.

                  I adapted my TwoWayFieldBrigde class and remove the method Wildcard() from TermContext.

                   

                  Find my TwoWayFieldBridge class

                   

                  package org.infinispan;
                  
                  import java.util.Iterator;
                  import org.apache.lucene.document.Document;
                  import org.apache.lucene.index.IndexableField;
                  import org.hibernate.search.bridge.LuceneOptions;
                  import org.hibernate.search.bridge.TwoWayFieldBridge;
                  import org.joda.time.DateTime;
                  import org.joda.time.format.DateTimeFormat;
                  
                  public class JodaTimeSplitBridge implements TwoWayFieldBridge {
                  
                  
                     
                  
                    DateTime datetime = (DateTime) value;
                    System.out.println(datetime.toString(DateTimeFormat.forPattern("yyyy/MM/dd")));
                    luceneoptions.addFieldToDocument(name,datetime.toString(DateTimeFormat.forPattern("yyyy/MM/dd")),document);
                  
                    Iterator<IndexableField> ifd = document.iterator();
                    while(ifd.hasNext()){
                    IndexableField fl = ifd.next();
                    System.out.println(fl.name()+" : "+fl.stringValue());
                    }
                  
                    }
                  
                  
                    @Override
                    public Object get(String name, Document document) {
                  
                    final IndexableField strdate = document.getField(name);
                    if(strdate != null){
                    DateTime value = DateTime.parse(strdate.stringValue(), DateTimeFormat.forPattern("yyyy/MM/dd"));
                    return value;
                    }
                    else {
                    return null;
                    }
                    }
                  
                  
                    @Override
                    public String objectToString(Object date) {
                  
                    DateTime datetime = (DateTime) date;
                    System.out.println(datetime.toString(DateTimeFormat.forPattern("yyyy/MM/dd")));
                    return datetime.toString(DateTimeFormat.forPattern("yyyy/MM/dd"));
                  
                  
                    }
                  }
                  

                   

                  Find my search class

                  package org.infinispan;
                  
                  
                  import java.lang.annotation.ElementType;
                  import java.util.Hashtable;
                  import java.util.Properties;
                  import java.util.UUID;
                  import java.util.Map.Entry;
                  
                  
                  import org.apache.lucene.search.Query;
                  import org.hibernate.search.cfg.Environment;
                  import org.hibernate.search.cfg.SearchMapping;
                  import org.hibernate.search.query.dsl.QueryBuilder;
                  import org.infinispan.configuration.cache.Configuration;
                  import org.infinispan.configuration.cache.ConfigurationBuilder;
                  import org.infinispan.configuration.cache.Index;
                  import org.infinispan.manager.DefaultCacheManager;
                  import org.infinispan.manager.EmbeddedCacheManager;
                  import org.infinispan.query.CacheQuery;
                  import org.infinispan.query.ResultIterator;
                  import org.infinispan.query.Search;
                  import org.infinispan.query.SearchManager;
                  import org.joda.time.DateTime;
                  import org.joda.time.format.DateTimeFormat;
                  
                  
                  
                  
                  public class Inf_01 {
                  
                  
                    public static void main(String[] args) {
                    // TODO Auto-generated method stub
                  
                  
                    EmbeddedCacheManager manager = new DefaultCacheManager();
                    ConfigurationBuilder cb = new ConfigurationBuilder();
                    SearchMapping mapping = new SearchMapping();
                  
                    /*mapping.analyzerDef("fr", StandardTokenizerFactory.class)
                    .filter(LowerCaseFilterFactory.class)
                    .filter(FrenchStemFilterFactory.class);*/
                  
                    mapping.entity(AuthorInfinispan.class).indexed().providedId()
                    .property("lastname", ElementType.METHOD).field()
                    .property("firstname", ElementType.METHOD).field()
                    .property("authoralias", ElementType.METHOD).field()
                    .property("website", ElementType.METHOD).field()
                    .property("biography", ElementType.METHOD).field()
                    .property("comment", ElementType.METHOD).field()
                    .property("borndate", ElementType.METHOD).field()
                    .property("creationdate", ElementType.METHOD).field();
                  
                  
                  
                    mapping.entity(CycleInfinispan.class).indexed().providedId()
                    .property("cycletitle", ElementType.METHOD).field()
                    .property("cycle", ElementType.METHOD).field()
                    .property("nbrvolume", ElementType.METHOD).field()
                    .property("comment", ElementType.METHOD).field()
                    .property("creationdate", ElementType.METHOD).field();
                  
                    mapping.entity(BookInfinispan.class).indexed().providedId()
                    .property("title", ElementType.METHOD).field()
                    .property("style", ElementType.METHOD).field()
                    .property("presentation", ElementType.METHOD).field()
                    .property("editor", ElementType.METHOD).field()
                    .property("collection", ElementType.METHOD).field()
                    .property("isbn", ElementType.METHOD).field()
                    .property("creationdate", ElementType.METHOD).field();
                  
                    Properties properties = new Properties();
                    properties.put(Environment.MODEL_MAPPING, mapping);
                  
                  
                  
                    Configuration c = cb.indexing()
                    .index(Index.LOCAL)
                    .withProperties(properties)
                    .persistence()
                    .passivation(false)
                    .addSingleFileStore()
                    .preload(true)
                    .shared(false)
                    .fetchPersistentState(true)
                    .ignoreModifications(false)
                    .purgeOnStartup(false)
                    .location("D:/infinispan")
                    .build();
                  
                    manager.defineConfiguration("book042015", c);
                  
                    Cache<UUID, IAuthor> cache = manager.getCache("book042015"); 
                  
                  
                  
                    SearchManager sm = Search.getSearchManager(cache);
                  
                    System.out.println(cache.getCacheConfiguration().indexing().index().isEnabled());
                  
                  
                    QueryBuilder qb = sm.buildQueryBuilderForClass(AuthorInfinispan.class).get();
                    Query q = qb.keyword().onField("creationdate").matching(new DateTime()).createQuery();
                    CacheQuery cq = sm.getQuery(q, AuthorInfinispan.class);
                    System.out.println(cq.getResultSize());
                  
                  
                    ResultIterator it = cq.iterator();
                    while(it.hasNext()){
                  
                    IAuthor author = (IAuthor) it.next();
                    System.out.println("Key : " + author.getID());
                    System.out.println("Author : " + author.getFirstName() + " " + author.getLastName());
                    System.out.println("Date de création : " + author.getCreationDate());
                    System.out.println("Nbr de Cycle : " + author.getListCycle().size());
                    System.out.println("Site Web : " + author.getWebSite());
                    System.out.println("Born Date : " + author.getBornDate());
                  
                    Hashtable<UUID, ICycle> listcycle = author.getListCycle();
                    for(Entry<UUID, ICycle> entrycycle : listcycle.entrySet()){
                    ICycle cycle = entrycycle.getValue();
                    System.out.println("--Cycle : " + cycle.getCycleTitle());
                  
                    Hashtable<UUID, IBook> listbook = cycle.getListBook();
                    for(Entry<UUID, IBook> entrybook : listbook.entrySet()){
                    IBook book = entrybook.getValue();
                    System.out.println("----Book : " + book.getTitle());
                    }
                  
                    }
                  
                  
                    System.out.println("-------------------------------------------------------------------");
                  
                    }
                  
                  
                    it.close();
                    cache.stop();
                    manager.stop();
                  
                  
                  
                  
                    }
                  
                  
                  }
                  

                   

                  Many Thanks,

                  Serge