Hibernate Search でインデックスを作成する必要があるドメイン オブジェクトが 1 つあります。DEV マシンでこのオブジェクトに対して FullTextQuery を実行すると、期待どおりの結果が得られます。次に、アプリを WAR にデプロイし、PROD サーバー (VPS) に展開します。PROD マシンで同じ「検索」を実行すると、期待した結果がまったく得られません (いくつかの結果が欠落しているようです)。
すべてが適切にインデックス化されていることを確認するために LUKE を実行しましたが、すべてが本来あるべき場所にあるように見えます... Hibernate Search は初めてなので、助けていただければ幸いです。
ここに私のドメインオブジェクトがあります:
package com.chatter.domain;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.apache.solr.analysis.LowerCaseFilterFactory;
import org.apache.solr.analysis.SnowballPorterFilterFactory;
import org.apache.solr.analysis.StandardTokenizerFactory;
import org.hibernate.search.annotations.AnalyzerDef;
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.Parameter;
import org.hibernate.search.annotations.Store;
import org.hibernate.search.annotations.TokenFilterDef;
import org.hibernate.search.annotations.TokenizerDef;
@Entity
@Table(name="faq")
@Indexed()
@AnalyzerDef(name = "customanalyzer",
tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
filters = {
@TokenFilterDef(factory = LowerCaseFilterFactory.class),
@TokenFilterDef(factory = SnowballPorterFilterFactory.class, params = {
@Parameter(name = "language", value = "English")
})
})
public class CustomerFaq implements Comparable<CustomerFaq>
{
private Long id;
@IndexedEmbedded
private Customer customer;
@Field(index=Index.TOKENIZED, store=Store.NO)
private String question;
@Field(index=Index.TOKENIZED, store=Store.NO)
private String answer;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
@ManyToOne(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
@JoinColumn(name="customer_id")
public Customer getCustomer()
{
return customer;
}
public void setCustomer(Customer customer)
{
this.customer = customer;
}
@Column(name="question", length=1500)
public String getQuestion()
{
return question;
}
public void setQuestion(String question)
{
this.question = question;
}
@Column(name="answer", length=1500)
public String getAnswer()
{
return answer;
}
public void setAnswer(String answer)
{
this.answer = answer;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
CustomerFaq other = (CustomerFaq) obj;
if (id == null)
{
if (other.id != null) return false;
} else if (!id.equals(other.id)) return false;
return true;
}
@Override
public int compareTo(CustomerFaq o)
{
if (this.getCustomer().equals(o.getCustomer()))
{
return this.getId().compareTo(o.getId());
}
else
{
return this.getCustomer().getId().compareTo(o.getCustomer().getId());
}
}
}
これは、私の Customer ドメイン オブジェクトのスニペットです。
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.Store;
import javax.persistence.Entity;
// ... other imports
@Entity
public class Customer
{
@Field(index=Index.TOKENIZED, store=Store.YES)
private Long id;
// ... other instance vars
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
そして私のpersistence.xml:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
<!-- value="create" to build a new database on each run; value="update" to modify an existing database; value="create-drop" means the same as "create" but also drops tables when Hibernate closes; value="validate" makes no changes to the database -->
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>
<property name="hibernate.connection.charSet" value="UTF-8"/>
<!-- Hibernate Search configuration -->
<property name="hibernate.search.default.directory_provider"
value="filesystem" />
<property name="hibernate.search.default.indexBase" value="C:/lucene/indexes" />
</properties>
</persistence-unit>
</persistence>
最後に、DAO で使用されているクエリを次に示します。
public List<CustomerFaq> searchFaqs(String question, Customer customer)
{
FullTextSession fullTextSession = Search.getFullTextSession(sessionFactory.getCurrentSession());
QueryBuilder queryBuilder = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(CustomerFaq.class).get();
org.apache.lucene.search.Query luceneQuery = queryBuilder.keyword().onFields("question", "answer").matching(question).createQuery();
org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery(luceneQuery, CustomerFaq.class);
List<CustomerFaq> matchingQuestionsList = fullTextQuery.list();
log.debug("Found " + matchingQuestionsList.size() + " matching questions");
List<CustomerFaq> list = new ArrayList<CustomerFaq>();
for (CustomerFaq customerFaq : matchingQuestionsList)
{
log.debug("Comparing " + customerFaq.getCustomer() + " to " + customer + " -> " + customerFaq.getCustomer().equals(customer));
log.debug("Does list already contain this customer FAQ? " + list.contains(customerFaq));
if (customerFaq.getCustomer().equals(customer) && !list.contains(customerFaq))
{
list.add(customerFaq);
}
}
log.debug("Returning " + list.size() + " matching questions based on customer: " + customer);
return list;
}