-->
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.  [ 2 posts ] 
Author Message
 Post subject: I don't understand filters :(
PostPosted: Wed Sep 30, 2009 9:43 am 
Newbie

Joined: Tue Sep 16, 2008 4:36 am
Posts: 11
Hi everybody,
I am trying very hard to understand how they filters work but unsuccessfully.

Before going in complicated stuff, I will show something very simple that I am trying to do and if you can help me figuring out what is going wrong I will very much appreciate. Also, I think it will help me understanding how it works.

So, I have requests. I want to do a fulltext search on several fields. It works just fine.
Now I also want to filter the results so that the user will be only able to see the requests he should see.

I have two filter rules for that:
1. The request shouldn't be closed
2. The client of the request shouldn't be himself

So here is the code I am using right now. needless to say, it doesn't work.

The request class:
Code:
package com.marroon.webapp.request.model;

import java.io.Serializable;
import java.util.Date;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;

import org.hibernate.search.annotations.Analyzer;
import org.hibernate.search.annotations.DocumentId;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.IndexedEmbedded;
import org.hibernate.search.annotations.Store;
import org.hibernate.validator.Length;
import org.hibernate.validator.NotEmpty;
import org.hibernate.validator.NotNull;

import com.marroon.webapp.admin.model.User;
import com.marroon.webapp.common.model.Category;
import com.marroon.webapp.common.model.Location;

@Entity
@Indexed
@Analyzer
public class Request implements Serializable{
   private static final long serialVersionUID = 3195217010000585539L;
   private Long id;
   private User client;
   private Set<Discussion> discussions;
   private Category category;
   private String title;
   private String shortDescription;
   private String addendum;
   private Double budget;
   private Date creationDate;
   private Date lastModificationDate;
   private Date deadline;
   private Location location;
   private boolean closed;
   
   public Request(User client, Category category,String title, String shortDescription,Double budget,Date deadline, String addendum){
      this.client = client;
      this.category = category;
      this.title = title;
      this.shortDescription = shortDescription;
      this.addendum = addendum;
      this.creationDate = new Date();
      this.lastModificationDate = new Date();
      this.budget = budget;
      this.deadline = deadline;
      this.closed = false;
   }
   @Override
   public String toString() {
      return getTitle();
   }
   @Field(store=Store.YES,index=Index.NO)
   public boolean isClosed() {
      return closed;
   }
   @Id
   @GeneratedValue(strategy=GenerationType.AUTO)
   @DocumentId
   public Long getId() {
      return id;
   }
   @Field(store=Store.YES,index=Index.NO)
   public Double getBudget(){
      return this.budget;
   }
   
   @ManyToOne(targetEntity=User.class)
   @IndexedEmbedded(prefix="client_",depth=1)
   public User getClient() {
      return client;
   }
   
   @ManyToOne(targetEntity=Category.class)
   public Category getCategory() {
      return category;
   }
   
   @NotNull @NotEmpty
   @Field(index=Index.TOKENIZED,store=Store.NO)
   public String getTitle() {
      return title;
   }
   
   @NotNull @NotEmpty
   @Length(max=2000)
   @Field(index=Index.TOKENIZED,store=Store.NO)
   public String getShortDescription() {
      return shortDescription;
   }
   @ManyToOne(targetEntity=Location.class)
   public Location getLocation(){
      return location;
   }
   
   @Field(index=Index.TOKENIZED,store=Store.NO)
   public String getAddendum() {
      return addendum;
   }
   public Date getCreationDate() {
      return creationDate;
   }
   
   public Date getLastModificationDate() {
      return lastModificationDate;
   }
   
   @OneToMany(mappedBy="request",fetch=FetchType.EAGER,cascade=CascadeType.ALL)
   public Set<Discussion> getDiscussions() {
      return discussions;
   }
   
   public Date getDeadline(){
      return deadline;
   }
   /* SET METHODS */
   public void setId(Long id) {
      this.id = id;
   }
   
   public void setClient(User client) {
      this.client = client;
   }
   public void setCategory(Category category) {
      this.category = category;
   }
   public void setTitle(String title) {
      this.title = title;
   }
   public void setShortDescription(String shortDescription) {
      this.shortDescription = shortDescription;
   }
   public void setAddendum(String addendum) {
      this.addendum = addendum;
   }
   public void setCreationDate(Date creationDate) {
      this.creationDate = creationDate;
   }
   public void setLastModificationDate(Date lastModificationDate) {
      this.lastModificationDate = lastModificationDate;
   }
   public void setDiscussions(Set<Discussion> discussions) {
      this.discussions = discussions;
   }
   public void setLocation(Location location){
      this.location = location;
   }
   public void setBudget(Double budget){
      this.budget = budget;
   }
   public void setDeadline(Date deadline){
      this.deadline = deadline;
   }
   public void setClosed(boolean closed) {
      this.closed = closed;
   }
   public Request(){}
}


The search bean
Code:
package com.marroon.webapp.request.bean;

import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.Query;

import org.apache.lucene.queryParser.ParseException;
import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.FullTextQuery;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.log.Log;

import com.marroon.webapp.admin.model.User;
import com.marroon.webapp.common.lucene.LuceneBuilder;
import com.marroon.webapp.common.lucene.filter.SearchClientFilter;
import com.marroon.webapp.common.model.Category;
import com.marroon.webapp.common.query.SQLBuilder;
import com.marroon.webapp.common.query.SQLFilterFactory;
import com.marroon.webapp.request.model.Request;

@Stateless
@Scope(ScopeType.EVENT)
@Name("SearchRequest")
public class SearchRequestBean implements SearchRequest {
   
   @In User user;
   @Logger Log log;
   @In FullTextEntityManager entityManager;

   @SuppressWarnings("unchecked")
   public List<Request> search(Category category, String search,
         Integer from, Integer max) throws ParseException{
      
      if(search == null || search.isEmpty()){
         SQLBuilder sql = new SQLBuilder("Request req")
                                          .addFilter(SQLFilterFactory.notIn("req", new SQLBuilder("Discussion disc")
                                          .setSelect("distinct disc.request")
                                          .addFilter(SQLFilterFactory.eq("disc.provider", user))))
                                          .addFilter(SQLFilterFactory.neq("req.client", user))
                                          .addFilter(SQLFilterFactory.eq("req.closed", Boolean.FALSE));
      
         if(category != null) sql.addFilter(SQLFilterFactory.eq("req.category", category));
         Query query = sql.getQuery(entityManager);
         if(from > 0) query.setFirstResult(from);
         if(max > 0) query.setMaxResults(max);
         
         return query.getResultList();
      }else{
         LuceneBuilder builder = new LuceneBuilder(Request.class,"title","shortDescription","addendum");
         FullTextQuery query = builder.getQuery(entityManager,search);
         SearchClientFilter client = new SearchClientFilter();
         client.setLogin(user.getLogin());
         query.setFilter(client);
         return query.getResultList();
      }
   }
}


And of course the SearchClientFilter:
Code:
package com.marroon.webapp.common.lucene.filter;

import java.io.IOException;

import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermDocs;
import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.Filter;
import org.apache.lucene.util.OpenBitSet;

public class SearchClientFilter extends Filter {
   private String login;
   public void setLogin(String login){
      this.login = login;
   }
   /**
    *
    */
   private static final long serialVersionUID = -5178325911912809515L;
   
   public DocIdSet getDocIdSet( IndexReader reader) throws IOException{
      
      OpenBitSet bitSet = new OpenBitSet( reader.maxDoc());
      TermDocs termDocs = reader.termDocs(new Term("client_login" ,login));
      while (termDocs.next()){
         bitSet.set(termDocs.doc());
      }
      return bitSet;
   }
}


The problem is the following, when I don't use the filter, the search works fine. when I use the SearchClientFilter, it doesn't work, meaning it doesn't return me any result when it should.

So I suppose that the indexing is performed because otherwise even without the filter it wouldn't work.

Also, a more general question. If I understand well how lucene works, it transforms everything into String. Does it uses toString() method to do so? For Example, how can I do a filter on a Boolean field?

Thank you very much in advance for trying to take me out of the fog.


Top
 Profile  
 
 Post subject: Re: I don't understand filters :(
PostPosted: Wed Sep 30, 2009 11:28 am 
Pro
Pro

Joined: Wed Oct 03, 2007 2:31 pm
Posts: 205
Hi

Everything in Lucene is stored as String. Lucene does not convert anything into a string. For example the Field class takes in String field name and String field value. You are responsible for converting values to String. Hibernate Search has builtin bridges that convert certain data types into String. Custom objects will require a custom bridge.

I'm guessing that you do not have a field "client_login" in the document that is being created as a result you're search does not work. Can I see the User class and does it have a field called "login"? That is the most likely scenario. I have implemented a whole bunch of filters based on user role and these work so Hibernate Search with lucene filtering works.

The filter that you've created looks fine as well. So I'm going to bet money that there is no field called client_login. Use Luke to inspect the document that is created.

I would recommend looking at Hibernate Search in Action or the documentation which provided an excellent diagram of how filters work in Lucene.

Hope that helps.


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