3

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

3 に答える 3

1

私のソフトウェアが indexBase を探していた実際の場所が間違っていたようです。

ログを調べたところ、indexBase のロード時に 2 つの異なる場所を参照していることに気付きました。

Hibernate Search がこの indexBase をロードしていた場所の 1 つは、"C:/Program Files/Apache Software Foundation/Tomcat 6.0/tmp/indexes" からでした。その後、少し後のログ (起動段階) で、それも同様であることがわかりました。 persistence.xml ファイル (「C:/lucene/indexes」) で設定した場所からロードします。

これに気付いたので、persistence.xml ファイルの場所を、(何らかの理由で) 探していた場所と一致するように変更しました。この 2 つが一致すると、ビンゴ、すべてが機能しました。

于 2013-08-20T16:12:12.167 に答える
0

盲目的なショットです。可能であれば、DEV env が PROD DB を指すようにして、期待する結果が得られるかどうかを確認してください。破棄して、実際の問題の前にいることを100%確信するだけです:)

于 2013-07-26T10:33:55.430 に答える
0

あなたのpersistence.xml構成で、あなたがMysqlの下にいることがわかります。異なる環境での同じクエリに関するいくつかのSQLの概念をグーグルで検索すると、同じクエリからキャッシュされたmysql結果セットが存在することがわかりましたが、これはcharsetなどの環境からの新しい変数に応じて変更される可能性があります。また、Mysql サーバーからこの機能を無効にすることもできます。

Hibernate In Action - Bauer, C. King, G. ページ 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からの出力を表示するには、クラスパス ( hibernate.propertiesまたはhibernate.cfg.xmlのすぐ隣) にlog4j.propertiesという名前のファイルが必要です。この例では、すべてのログ メッセージをコンソールに送信します。

### ログメッセージを 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

### ルートロガーオプション ###

log4j.rootLogger=warn, stdout

### Hibernate ロギング オプション ###

log4j.logger.net.sf.hibernate=info

### JDBC バインド パラメータのログ記録 ###

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

### PreparedStatement キャッシュ アクティビティのログ ###

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

この構成では、実行時に多くのログ メッセージが表示されることはありません。log4j.logger.net.sf.hibernateカテゴリの info を debug に置き換えると、Hibernate の内部動作が明らかになります。ログの書き込みは、実際のデータベース アクセスよりもはるかに遅くなります。最後に、hibernate.properties、hibernate.cfg.xml、および log4j.properties 構成ファイルがあります。

于 2013-07-28T09:25:04.463 に答える