原文地址:http://www.abstractec.co.uk/blog/index.php?itemid=57
在这篇文章里,我将描述如何将Hibernate Search添加到JBoss Seam里面。
首先,我们需要将相关配置添加到persistence.xml中,如下:
- <property name="hibernate.search.default.directory_provider" value="org.hibernate.search.store.FSDirectoryProvider" />
- <property name="hibernate.search.default.indexBase" value="[/path/to/your/location/directory]" />
- <property name="hibernate.ejb.event.post-insert" value="org.hibernate.search.event.FullTextIndexEventListener" />
- <property name="hibernate.ejb.event.post-update" value="org.hibernate.search.event.FullTextIndexEventListener" />
- <property name="hibernate.ejb.event.post-delete" value="org.hibernate.search.event.FullTextIndexEventListener" />
这样我们就设置好了类路径、索引路径、索引操作监听器路径。下面,我们需要添加hibernate-search.jar、hibernate-commons-annotations.jar和lucene-core.jar到你的ear里面。
好了,现在,我们需要告诉Hibernate Search哪个对象被索引,并且我们会对哪些属性感兴趣。
- @Entity
- @Name("product")
- @Indexed
- public class Product implements Serializable {
- static final long serialVersionUID = 1l;
- @Id @GeneratedValue @DocumentId
- private Long id;
- @NotNull
- @Field(index = Index.TOKENIZED)
- private String name;
- @NotNull
- @Field(index = Index.TOKENIZED)
- private String description;
-
- }
@Indexed注解用来告诉Hibernate Search该持久类是拥有索引的。@DocumentId注解用来标明这个属性是这个对象的ID,并且未被编入索引。此外,我们还有两个属性,分别是name和description。这两个属性都用@Field标注,这样Hibernate Search就被允许分析处理这两个属性。其他可选的属性有Index.NO(不要被分析)、Index.UN_TOKENIZED(不要被分析器预先处理)、Index.NO_NORM(不需要存储的普通属性)。
现在,我们已经拥有了Lucene的所有索引,我们还需要一个搜索的方法。所以我们需要建立一个SearchManager类。
- @Name("SearchManager")
- public class SearchManager {
- @In
- private FullTextEntityManager entityManager;
- private String searchPattern;
-
- public List getResults() {
- Map boostFields = new HashMap(2);
-
-
- boostFields.put("name", 4f);
- String[] productFields = {"name", "description"};
- QueryParser parser = new MultiFieldQueryParser(productFields, new StandardAnalyzer(), boostFields);
- parser.setAllowLeadingWildcard(true);
- Query luceneQuery;
- try {
- luceneQuery = parser.parse(searchPattern);
- } catch (ParseException pe) {
- log.error("found a problem in search", pe);
- return null;
- }
-
- List products =
- entityManager.createFullTextQuery(luceneQuery, Product.class).
- setMaxResults(20).getResultList();
- return products;
- }
- }
好了,现在我们可以创建search.xhtml文件,用来显示搜索结果了。下面是该文件的一个片段。
- <rich:dataGrid value="#{SearchManager.results}" var="garage">
- [ loop over the values ]
- </rich:dataGrid>
然后,在pages.xml中添加一个到search.xhtml的入口。
- <page view-id="/search.xhtml">
- <param name="searchPattern" value="#{SearchManager.searchPattern}"/>
- </page>
还剩下一个步骤。我们需要添加一个搜索框到菜单里面。如果你使用了Seam的默认布局,你就会看见/view/layout文件夹下面有一个menu.xhtml文件。如果没有找到,只需要将下面这一段添加到你需要的地方:
- <h:form id="search_form">
- <h:inputText id="searchPattern" required="true" value="#{SearchManager.searchPattern}" />
- <h:commandButton action="/search.xhtml" value="search"></h:commandButton>
- </h:form>
现在,你可以开始搜索你想要的对象了。是不是非常简单?但是,如果对象的一个属性是用来表示这个对象是否能显示在页面上,那应该怎么办?好的,在这种情况下,你需要添加一个过滤器。过滤器都继承自org.apache.lucene.search.Filter类。
想象一下,我们在产品类上有一个属性是用来标明产品的状态的,这个属性有三种值"L"表示有效的产品,"D"表示被删除的产品,"P"表示待发布的产品。显然,在用户搜索的时候,我们只想显示出可见的产品。所以我们需要添加一个过滤器:
- public class LiveProductFilter extends Filter {
- private static final long serialVersionUID = 1l;
- public BitSet bits(IndexReader reader) throws IOException {
- BitSet bitSet = new BitSet( reader.maxDoc() );
- TermDocs termDocs = reader.termDocs( new Term("status", "L") );
- while ( termDocs.next() ) {
- bitSet.set( termDocs.doc() );
- }
- return bitSet;
- }
- }
为了让Hibernate Search能够找到我们在产品类上添加的过滤器,我们需要添加下面这个注解:
@FullTextFilterDefs ( { @FullTextFilterDef(name="liveProduct", impl = LiveProductFilter.class, cache=false) })好了,就写到这里。
想要了解更多信息,请参考Hibernate Search文档