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.