Hibernate Search在具有相同数据库的DEV和PROD之间表现不同

时间:2013-07-10 23:29:32

标签: java lucene hibernate-search

我有一个需要Hibernate Search索引的域对象。当我在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());
    }
  }
}

以下是我的客户域对象的片段:

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;
  }

3 个答案:

答案 0 :(得分:1)

看起来我的软件查找indexBase的实际位置不正确。

当我浏览日志时,我注意到在加载indexBase时它指的是两个不同的位置。

Hibernate Search加载此indexBase的一个位置来自“C:/ Program Files / Apache Software Foundation / Tomcat 6.0 / tmp / indexes”,然后稍后在日志中(在启动阶段)我看到了它也是从我在persistence.xml文件中设置的地方加载的(“C:/ lucene / indexes”)。

所以意识到这一点,我刚刚更改了persistence.xml文件中的位置,以匹配它(由于某种原因)的位置。一旦这两个匹配,BINGO,一切正常!

答案 1 :(得分:0)

只是盲目拍摄,如果可能的话,让您的DEV env指向PROD DB,看看您是否得到了您期望的结果。 只有放弃并且100%确定你在真正的问题面前:)

答案 2 :(得分:0)

我可以在你的persistence.xml配置中看到你在Mysql下。在不同的环境中搜索关于相同查询的一些sql概念我发现存在来自相同查询的缓存的mysql结果集,但是这个缓存可能会根据来自环境的新变量(如charset)而发生变化。您也可以从Mysql服务器中禁用此功能。

引自Hibernate In Action - Bauer,C。King,G。Page 55(第2.4.3节记录)

但是,特别是面对异步行为,可以快速调试Hibernate 让你迷路您可以使用日志记录来获取Hibernate内部的视图。 我们已经提到了* hibernate.show_sql *配置参数, 这通常是疑难解答时的第一个停靠点。有时是SQL 单靠不足;在这种情况下,你必须挖一点更深的。 Hibernate使用Apache commons-logging 来记录所有有趣的事件 将输出定向到Apache log4j 的抽象层(如果你输入 log4j.jar 在您的类路径中)或 JDK1.4 日志记录(如果您在JDK1.4或更高版本下运行, log4j不存在)。我们建议 log4j ,因为它更成熟,更受欢迎, 并且在更积极的发展下。 要查看 log4j 的任何输出,您需要一个名为 log4j.properties 的文件 classpath(紧邻 hibernate.properties hibernate.cfg.xml )。这个例子 将所有日志消息定向到控制台:

###将日志消息直接发送到stdout ###

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### root logger选项###

log4j.rootLogger=warn, stdout

### Hibernate日志记录选项###

log4j.logger.net.sf.hibernate=info

### log JDBC绑定参数###

log4j.logger.net.sf.hibernate.type=info

### log PreparedStatement缓存活动###

log4j.logger.net.sf.hibernate.ps.PreparedStatementCache=info

使用此配置,您不会在运行时看到许多日志消息。更换 调试 log4j.logger.net.sf.hibernate 类别的信息将显示 Hibernate的内部工作原理。确保在生产环境中不这样做 - 写日志将比实际的数据库访问慢得多。 最后,你有hibernate.properties,hibernate.cfg.xml和 log4j.properties配置文件。