详解Java的Hibernate框架中的搜索工具的运用

hibernate提供了全文索引功能,非常棒,这里简要介绍下它的用法,
1. 在pom.xml引入包依赖

<dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-search-orm</artifactId>
      <version>${hibernate-search.version}</version>
    </dependency>

    <dependency>
      <groupId>org.apache.lucene</groupId>
      <artifactId>lucene-analyzers-smartcn</artifactId>
      <version>${lucene.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.lucene</groupId>
      <artifactId>lucene-queryparser</artifactId>
      <version>${lucene.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.lucene</groupId>
      <artifactId>lucene-analyzers-phonetic</artifactId>
      <version>${lucene.version}</version>
    </dependency>

hibernate配置 search index保存路径

 <bean id="sessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"
    destroy-method="destroy">
    <property name="dataSource" ref="poolingDataSource" />
    <property name="configLocation">
      <value> classpath:hibernate.cfg.xml </value>
    </property>
    <property name="hibernateProperties">
      <props>
        <prop key="hibernate.dialect">${hibernate.dialect}</prop>
        <!-- Booleans can be easily used in expressions by
           declaring HQL query substitutions in Hibernate configuration -->
        <prop key="hibernate.query.substitutions">true 'Y', false 'N'</prop>
        <!-- http://ehcache.org/documentation/integrations/hibernate -->
        <!-- http://www.tutorialspoint.com/hibernate/hibernate_caching.htm -->
        <prop key="hibernate.cache.use_second_level_cache">true</prop>
        <!-- org.hibernate.cache.ehcache.EhCacheRegionFactory -->
        <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
        <!-- hibernate只会缓存使用load()方法获得的单个持久化对象,如果想缓存使用findall()、 list()、Iterator()、createCriteria()、createQuery()
                等方法获得的数据结果集的话,就需要设置hibernate.cache.use_query_cache true -->
        <prop key="hibernate.cache.use_query_cache">true</prop>
        <prop key="net.sf.ehcache.configurationResourceName">ehcache-hibernate.xml</prop>
        <!-- Hibernate Search index directory -->
        ***<prop key="hibernate.search.default.indexBase">indexes/</prop>***
      </props>
    </property>
  </bean>

对需要搜索的类加上Indexed Annotation,然后对类中可以被搜索的字段加上@Field Annotation,通常Enum字段不需要Analyzer进行词法分析,其他字段则需要,对于不需要Projection(返回部分字段)的情况下,不需要在index中存储实际数据。可以通过AnalyzerDef来定义不同的词法分析器以及对于的特殊词过滤器

@Indexed
@AnalyzerDef(
    name="enTopicAnalyzer",
    charFilters={
      @CharFilterDef(factory=HTMLStripCharFilterFactory.class)
    },
    tokenizer=@TokenizerDef(factory=StandardTokenizerFactory.class),
    filters={
      @TokenFilterDef(factory=StandardFilterFactory.class),
      @TokenFilterDef(factory=StopFilterFactory.class),
      @TokenFilterDef(factory=PhoneticFilterFactory.class,
        params = {
          @Parameter(name="encoder", value="DoubleMetaphone")
        }),
      @TokenFilterDef(factory=SnowballPorterFilterFactory.class,
        params = {
          @Parameter(name="language", value="English")
        })
      }
  )
public class Topic {

  ......
  @Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
  @Analyzer(definition = "enTopicAnalyzer")
  private String title;
  ......
  @Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
  @Analyzer(definition = "enTopicAnalyzer")
  private String content;
  ......
  @Enumerated(EnumType.STRING)
  @Field(index=Index.YES, analyze=Analyze.NO, store=Store.NO, bridge=@FieldBridge(impl=EnumBridge.class))
  private TopicStatus status;
  ...
  }

通过代码对已有数据创建index

ApplicationContext context = new ClassPathXmlApplicationContext("spring-resources.xml");

    SessionFactory sessionFactory = (SessionFactory) context.getBean("sessionFactory");

    Session sess = sessionFactory.openSession();
    FullTextSession fullTextSession = Search.getFullTextSession(sess);
    try {
      fullTextSession.createIndexer().startAndWait();
    } catch (InterruptedException e) {
       LOG.error(e.getMessage(), e);
    } finally {
      fullTextSession.close();
    }
    ((AbstractApplicationContext)context).close();

创建查询fulltextsession,按照query条件获取结果

 FullTextSession fullTextSession = Search
        .getFullTextSession(getSession());

    QueryBuilder queryBuilder = fullTextSession.getSearchFactory()
        .buildQueryBuilder().forEntity(Show.class).get();
    org.apache.lucene.search.Query luceneQuery = null;

      luceneQuery = queryBuilder.keyword()// .wildcard()
          .onFields("title", "content").matching(query.getKeyword())
          // .matching("*" + query.getKeyword() + "*")
          .createQuery();

    FullTextQuery hibernateQuery = fullTextSession.createFullTextQuery(
        luceneQuery, Show.class);
    return hibernateQuery.list();

note:
1. 在一次测试过程中,修改了value object,添加了新的index,忘记了rebuildIndex,结果unit test没问题,生成环境就出错了。
2. 搜索还不是很强大,比如搜索测,含有测试的结果可能就搜索不出来

中文词法分析

hibernate search底层使用Lucene,所以Lucene可以使用的中文分词,hibernate search都可以用来支持中文词法分析,比较常用的词法分析器包括paoding,IKAnalyzer,mmseg4j 等等。具体可以参考分词分析 最近分析。hibernate search默认的分词器是org.apache.lucene.analysis.standard.StandardAnalyzer,中文按字分词,显然不符合我们的需求。
这里介绍一下如何在hibernate中配置中文分词,选择的是Lucene自带的中文分词–。使用可以通过3种方式,一种是在hibernate的配置文件设置词法分析方法,另外一种是在每个需要被搜索的类中定义分词方法,最后一种是对单个字段配置。这里介绍下前2种的配置方式。
hibernate配置方式:

<property name="hibernate.search.analyzer"> org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer</property>

被搜索类配置中文分词:

@Indexed
@Analyzer(impl=SmartChineseAnalyzer.class)

同时需要在maven中引入相关包依赖

<dependency>
      <groupId>org.apache.lucene</groupId>
      <artifactId>lucene-analyzers-smartcn</artifactId>
      <version>${lucene.version}</version>
    </dependency>

多条件查询
hibernate search可以通过多组合条件来实现多条件查询,这里简单介绍一下多条件查询的一个实践。
如果只是单个条件查询,那么这个查询就可以很简单

luceneQuery = queryBuilder.keyword().onFields("title", "content").matching(query.getKeyword()).createQuery()

如果是多条件并查询,那么就需要使用到Must Join,如果是多条件或查询,就需要使用should Join,这里举个Must Join的例子

//must true
MustJunction term = queryBuilder.bool().must(queryBuilder.keyword()
          .onFields("title", "content")   .matching(query.getKeyword()).createQuery());
//must false
 term.must(queryBuilder.keyword()
              .onField("status")             .matching(query.getExcludeStatus()).createQuery()).not();

完整例子:

private FullTextQuery findByKeywordQuery(TopicQuery query) {
    FullTextSession fullTextSession = Search
        .getFullTextSession(getSession());

    QueryBuilder queryBuilder = fullTextSession.getSearchFactory()
        .buildQueryBuilder().forEntity(Topic.class).get();
    org.apache.lucene.search.Query luceneQuery = null;
    if (null == query.getStatus() && null == query.getUsername() && null == query.getExcludeStatus()) {
      luceneQuery = queryBuilder.keyword()// .wildcard()
          .onFields("title", "content").matching(query.getKeyword())
          // .matching("*" + query.getKeyword() + "*")
          .createQuery();
      if(LOG.isDebugEnabled()){
        LOG.debug("create clean keyword search query: " + luceneQuery.toString());
      }
    } else {
      MustJunction term = queryBuilder.bool().must(queryBuilder.keyword()
          .onFields("title", "content")   .matching(query.getKeyword()).createQuery());
      if(null != query.getStatus()){
        term.must(queryBuilder.keyword()
              // .wildcard()
              .onField("status")
              .matching(query.getStatus()).createQuery());
      }
      if(null != query.getExcludeStatus()){
        term.must(queryBuilder.keyword()
              .onField("status")
              .matching(query.getExcludeStatus()).createQuery()).not();
      }
      if(null != query.getUsername()){
        term.must(queryBuilder.keyword()
              // .wildcard()
              .onField("owner.username")
               .ignoreFieldBridge()
              .matching(query.getUsername()).createQuery());
      }
      luceneQuery =term.createQuery();
      if(LOG.isDebugEnabled()){
        LOG.debug("create complicated keyword search query: " + luceneQuery.toString());
      }
    }
    // BooleanQuery
    FullTextQuery hibernateQuery = fullTextSession.createFullTextQuery(
        luceneQuery, Topic.class);
    return hibernateQuery;
  }
(0)

相关推荐

  • 浅析java 循序与二元搜索算法

    循序搜索法 就是一个一个去比较,找到时返回: 二元搜索法 二元搜索算法是在排好序的数组中找到特定的元素. 首先, 比较数组中间的元素,如果相同,则返回此元素的指针,表示找到了. 如果不相同, 此函数就会继续搜索其中大小相符的一半,然后继续下去. 如果剩下的数组长度为0, 则表示找不到,那么函数就会结束. 实现代码: 复制代码 代码如下: package com.zc.manythread; import java.util.Random; import java.util.Scanner; /*

  • 基于Lucene的Java搜索服务器Elasticsearch安装使用教程

    一.安装Elasticsearch Elasticsearch下载地址:http://www.elasticsearch.org/download/ ·下载后直接解压,进入目录下的bin,在cmd下运行elasticsearch.bat 即可启动Elasticsearch ·用浏览器访问: http://localhost:9200/   ,如果出现类似如下结果则说明安装成功: { "name" : "Benedict Kine", "cluster_na

  • java实现单词搜索迷宫游戏

    本文实例讲述了java实现单词搜索迷宫游戏.分享给大家供大家参考.具体分析如下: 我们在杂志上,经常能够看到找单词的小游戏,在一个二维表格中,存在各种字母,我们可以从八个方向找单词.这个用计算机处理十分方便,但是,算法的好坏很重要,因为要是用蛮力算法实现,那么耗费的时间是不可想象的. 这是数据结构与问题求解Java语言描述一书中给的实现思路 完整代码如下,注释写的很明白了 import java.io.BufferedReader; import java.io.FileReader; impo

  • java实现简单的搜索引擎

    记得java老师曾经说过百度的一个面试题目,大概意思是"有1W条无序的记录,如何从其中快速的查找到自己想要的记录".这个就相当于一个简单的搜索引擎.最近在整理这一年的工作中,自己竟然已经把这个实现了,今天对其进一步的抽象,和大家分享下. 先写具体的实现代码,具体的实现思路和逻辑写在代码之后. 搜索时用于排序的Bean /** *@Description: */ package cn.lulei.search.engine.model; public class SortBean { p

  • java asp分析各种搜索引擎的关键字,自动识别url 中关键字的编码

    所以必须要通过编码后的关键字,例如"解析关键字编码"在google里面输入搜索,得到编码后的"%E8%A7%A3%E6%9E%90%E5%85%B3%E9%94%AE%E5%AD%97%E7%BC%96%E7%A0%81" 1.从以上地址中解析出关键字部分. 2.通过编码后的关键字获取编码时的编码名称(如:gbk,utf-8等等) 3.用URLdecode(keywords,encodeCode)来解码得到对应的关键字. 以下是java代码的实现: 复制代码 代码如

  • 使用Java的Lucene搜索工具对检索结果进行分组和分页

    使用GroupingSearch对搜索结果进行分组 Package org.apache.lucene.search.grouping Description 这个模块可以对Lucene的搜索结果进行分组,指定的单值域被聚集到一起.比如,根据"author"域进行分组,"author"域值相同的的文档分成一个组. 进行分组的时候需要输入一些必要的信息: 1.groupField:根据这个域进行分组.比如,如果你使用"author"域进行分组,那么

  • 详解Java的Hibernate框架中的搜索工具的运用

    hibernate提供了全文索引功能,非常棒,这里简要介绍下它的用法, 1. 在pom.xml引入包依赖 <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-search-orm</artifactId> <version>${hibernate-search.version}</version> </dependency> &

  • 详解Java的Hibernate框架中的缓存与二级缓存

    缓存 今天我们就来讲一下hibernate中实体状态和hibernate缓存.  1)首先我们先来看一下实体状态:  实体状态主要分三种:transient,persitent,detached.  看英文应该就大概明白了吧.  transient:是指数据还没跟数据库中的数据相对应.  persistent:是指数据跟数据库中的数据相对应,它的任何改变都会反映到数据库中.  detached:是指数据跟数据库中的数据相对应,但由于session被关闭,它所做的修改不会对数据库的记录造成影响.

  • 详解Java的Hibernate框架中的注解与缓存

    注解 Hibernate注解是一个没有使用XML文件来定义映射的最新方法.可以在除或替换的XML映射元数据使用注解. Hibernate的注解是强大的方式来提供元数据对象和关系表的映射.所有的元数据被杵到一起的代码POJO java文件这可以帮助用户在开发过程中同时要了解表的结构和POJO. 如果打算让应用程序移植到其他EJB3规范的ORM应用程序,必须使用注解来表示映射信息,但仍然如果想要更大的灵活性,那么应该使用基于XML的映射去. 环境设置Hibernate注释 首先,必须确保使用的是JD

  • 详解Java的Hibernate框架中的缓存与原生SQL语句的使用

    Hibernate缓存 缓存是所有关于应用程序的性能优化和它位于应用程序和数据库之间,以避免数据库访问多次,让性能关键型应用程序有更好的表现. 缓存对Hibernate很重要,它采用了多级缓存方案下文所述: 第一级缓存: 第一级缓存是Session的缓存,是一个强制性的缓存,通过它所有的请求都必须通过. Session对象不断自身的动力的对象,提交到数据库之前. 如果发出多个更新一个对象,Hibernate试图拖延尽可能长的时间做了更新,以减少发出的更新SQL语句的数量.如果您关闭会话,所有被缓

  • 详解Java的Hibernate框架中的List映射表与Bag映射

    List映射表 List列表是一个java集合存储在序列中的元素,并允许重复的元素.此接口的用户可以精确地控制,其中列表中的每个元素插入.用户可以通过他们的整数索引访问元素,并搜索列表中的元素.更正式地说,列表通常允许对元素e1和e2,使得e1.equals(e2),它们通常允许多个null元素,如果他们允许的null元素. List列表被映射在该映射表中的<list>元素,并将java.util.ArrayList中初始化. 定义RDBMS表: 考虑一个情况,需要员工记录存储在EMPLOYE

  • 详解Java的Hibernate框架中的Interceptor和Collection

    Interceptor 讲到Interceptor,相信熟悉struts2的童鞋肯定不会陌生了,struts2可以自定义拦截器进行自己想要的一系列相关的工作.而这里我们说的Interceptor也是差不多相似的功能.  废话不说,直接来代码:  下面这个是MyInterceptor类,它实现了Interceptor接口: public String onPrepareStatement(String arg0) { return arg0; } public boolean onSave(Obj

  • 详解Java的Hibernate框架中的set映射集与SortedSet映射

    Set 集合Set是一个java集合不包含任何重复的元素.更正式地说,Set不包含任何元素对e1和e2,使得e1.equals(e2),和至多一个空元素.所以被添加到一组对象必须实现equals()和hashCode()方法,使Java可以判断任何两个元素/对象是否是相同的. 集被映射到与映射表中<set>元素,并在java.util.HashSet中初始化.可以使用Set集合在类时,有一个集合中不需要重复的元素. 定义RDBMS表: 考虑一个情况下,我们需要我们的员工记录存储在EMPLOYE

  • 详解Java的Spring框架中的事务管理方式

    数据库事务是被当作单个工作单元的操作序列.这些操作要么全部完成或全部不成功.事务管理是面向企业应用程序,以确保数据的完整性和一致性RDBMS中的重要组成部分.事务的概念可以用下面的描述为ACID四个关键属性来描述: 原子性: 一个事务应该被视为单个操作单元表示的操作的任一整个序列是成功的或不成功的. 一致性: 这代表了数据库的参照完整性,在桌等唯一主键的一致性 隔离性: 可能有很多事务处理相同的数据集的同时,每个事务都应由他人隔离,以防止数据损坏. 持久性: 一旦事务完成,本次事务的结果必须作出

  • 详解Java的Hibernat框架中的Map映射与SortedMap映射

    Map映射 Map映射是一个java集合存储在键 - 值对的元素,并且不允许在列表中重复的元素. Map接口提供三种collection视图,允许Map内容看作是一组键-值集合,或者设置键 - 值映射关系. Map被映射到映射表中一个<map>元素和无序的地图可以在java.util.HashMap中被初始化. 定义RDBMS表: 考虑一个情况,我们需要员工记录存储在EMPLOYEE表,将有以下结构: create table EMPLOYEE ( id INT NOT NULL auto_i

  • 详解Java的MyBatis框架中的事务处理

    一.MyBatis单独使用时,使用SqlSession来处理事务: public class MyBatisTxTest { private static SqlSessionFactory sqlSessionFactory; private static Reader reader; @BeforeClass public static void setUpBeforeClass() throws Exception { try { reader = Resources.getResourc

随机推荐