分享

传智播客--全文检索Lucene/Compass框架使用3(9.24)_传智播客学习笔记_...

 追梦的浪人 2011-05-20

接下来看一下有关查询的知识,前面为了比较好的理解,我一直使用的查询字符串的形式来实现的,将一个查询字符串可以封装为一个Query对象。这里我们开始正式的接触查询的相关知识,只要还是使用对象的方式来进行查询。关于查询对象有很多,这里我们主要学习以下几个查询对象:TermQuery、RangeQuery、WildcardQuery、PhraseQuery和BooleanQuery。

       首先看一下TermQuery对象,Term对应的是查询字符串中的一个关键字对象。构建一个TermQuery对象只要传一个Term对象就可以了,查询的结果和使用字符串查询是一样的。如:Term term=new Term("content","知识");    TermQuery query=new TermQuery(term);接下来就是RangeQuery对象,主要是针对范围的查询,所以构建这样的对象需要至少提供两个Term,来表示一个范围,例如:Term highTerm=new Term("size","2000");    Term lowTerm=new Term("size","1000");

      RangeQuery query=new RangeQuery(lowTerm,highTerm,true);这里有一点千万要注意,作为范围的参数应该是数值型的才具有比较价值,但是我们在这里需要传递的参数是字符串型,因此这里其实可以使用前面所介绍的DateTools和NumberTools类来进行相应放入转化。WildcardQuery对象是进行通配符查询的,主要是针对关键字不是非常清楚的情况,可以使用*代表人一个字符,可以使用?代表一个字符,这里有一点要注意?和*,必须是英文的符号,在进行中文的搜索的时候经常会犯这样的错误,一定要注意。还有就是PhraseQuery短语查询,主要是针对有多个关键字的时候,可以使用add方法,将需要查询的每一个关键字封装为Term对象传递进来,还可以使用setSlop方法来设置这两个关键字的间隔数目。最后一个就是很常用的布尔查询BooleanQuery,布尔查询其实就是封装了几个其他的查询对象并且指定这些查询的关系,有MUST ,MUST NOT,SHOULD等类型,其实经常会使用。这就是几个常用的Query的子类,在使用的时候根据不同的需要选择不同的对象很方便,他们对应的查询字符串可以直接打印Query对象就可以看到查询字符串了。还有以下需要注意:MUST和MUST:取得连个查询子句的交集。MUST和MUST_NOT:包含MUST并且查询结果中不包含MUST_NOT的检索结果。SHOULD与SHOULD,表示“或”关系,最终检索结果为所有检索子句的并集。MUST和SHOULD:此时SHOULD无意义,结果为MUST子句的检索结果。

MUST_NOT和MUST_NOT:无意义,检索无结果。MUST_NOT和SHOULD:此时SHOULD相当于MUST,结果同MUST和MUST NOT。单独使用SHOULD:结果相当于MUST。

单独使用MUST_NOT:无意义,检索无结果。

至于查询的语法也就十分简单了,简要的了解一下就可以了,“+”与“-”:表示后面的条件是“MUST”,还是“MUST_NOT”。“AND”:“OR”:“NOT”:“+”、“-”与“AND”、“OR”同时使用时,可以使用括号“(”和“)”,对逻辑进行组合。

       我们查询的信息肯定要按照相关度排序才可以,越靠前的越符合我们的意思,因此这个相关度我们也可以人为的进行修改的,这里就是主要使用的这个boost参数来指定,Document的boost属性:Document. setBoost(float boost)。Field的boost属性:Field. setBoost(float boost)。查询时指定: MultiFieldQueryParser(String[] fields, Analyzer analyzer, Map boosts)。此外还有一种不是按照相关度来排序的,可以按照某一个Field来进行排序可以使用Sort对象的sort方法来进行指定。关于过滤器主要的功能就是过滤,如:RangeFilter,可以对搜索出来的结果进行过滤。

接下来的一个重点就是Compass,Compass是对Lucene进行的封装。Compass对于Lucene,就好像Hibernate对于Jdbc。在使用时用到的类(除分词器外),都是使用的Compass的。使用的过程就是添加jar包,定义可搜索的对象

a)        应使用一个单独的类,专门用于搜索的,只需定义在搜索结果页面中需要显示(用到)的属性。

b)        在类上声明 @searchable, 说明这是可以被搜索的类

c)        在有唯一标识作用的属性上声明@searchableId,这个必须要有。

d)        在属性(getter)上声明@searchProperty,并指定Store与Index策略,还可以指定boost

再进行初始化Compass,compass的使用和Hibernate的使用非常相似,CompassConfiguration cfg = new CompassConfiguration();cfg.setConnection("./index/"); // 设置索引目录cfg.addClass(Post.class);   compass = cfg.buildCompass();Compass提供的基本上就是完全面向对象的实现,只要是使用hibernate比较熟练的,那么使用Compass应该就简单了,它把大量的操作进行了相应的封装处理,比如创建可以使用create方法,删除索引可以使用delete方法,更新索引使用的是save方法,如果要进行查询就是使用的CompassSession.get和CompassSession.load方法,这两个的区别就是如果不存在指定的id的资源,get会返回null,而load会抛一个异常.。可以直接在配置文件中进行配置一些信息,例如包括分词器和高亮器等,还可以使用程序进行硬编码的方式来进行相应的配置,例如:可以使用配置:compass.engine.analyzer.[analyzer name].type指定内置的名称,或者是指定分词器的全限定类名。对于高亮器也是一样的,使用设置默认highlighter的前缀:"compass.engine.highlighter.default.formatter.simple.pre",设置默认highlighter的后缀:"compass.engine.highlighter.default.formatter.simple.post"。至于这些详细的配置信息,没有必要死记硬背,可以查看相应的官方文档,Compass的相应的官方文档写的比较详细。

       最后还有一个知识点就是关于CompassTemplate。在使用Hibernate的时候我们发现其实每次的使用,很多代码都是重复的,只有那么一两句的代码是有用的,那么我们就么有必要每次都写这么多代码,这个过程是非常的繁琐的。同样我们在使用Compass的时候,也是遇到了同样的问题,大量的重复性的劳动。可能有人不是很清楚,这里我简单的举一个小的例子,public void save(Article a) {

      CompassSession session = null;

      CompassTransaction tx = null;

      try {

         session = compass.openSession();

         tx = session.beginTransaction();

         session.create(a);

         tx.commit();

      } catch (CompassException e) {

         if (tx != null) {

           tx.rollback();

        }

         throw new RuntimeException(e);

      } finally {

         if (session != null) {

           session.close();

        }

      }

   }

这个方法就可以看到其实有用的只有session.create(a);这句代码,至于其他的代码都是和其他的方法所公用的,显然这不是我们想要的。那么该怎么解决这个问题呢?这里就牵涉一种软件设计的思想。这种思想是很值得借鉴的,只要是类似这样的问题的编码我们都可以使用。我最初的想法和大家都一样,就是新建两个方法,每次调用这两个方法,但是这是不行的,应为这里面的整个代码是有关系的,比如try…..catch…是不能进行分割的。如果是JS的话我们还可以直接传递一句代码给某个函数来执行,通过函数就可以完成了,但是在Java中是没有这样的函数的。那么我们该如何解决这个问题呢?

   解决的方法我是根本想不到的,只不过能够坚持进行总结慢慢的就可以记住了。可以使用一个接口和一个内部类来实现,这种方式非常的巧妙,当然理解起来也是有一定的难度的。就以上面的例子为例,首先我们需要定义一个execute()方法,这个方法就是提供的这个这些基本的操作,然后在中间的一句关键代码,以一个接口的内部类的形式来传递,因此这里的参数就是一个CallBack的接口的实现类,有了这个接口的实现类,就可以根据实际情况调用其相应的处理代码。public void excute(CallBack callback) {

      CompassSession session = null;

      CompassTransaction tx = null;

      try {session = compass.openSession();

         tx = session.beginTransaction();

         callback.doInSession(session);

         tx.commit();

      } catch (CompassException e) {

         if (tx != null) {

           tx.rollback();

        }

         throw new RuntimeException(e);

      } finally {

         if (session != null) {

           session.close();

        }

      }

   }

那么在使用的时候就非常简单了,如下所示:   public void save(final Article a) {

      this.excute(new CallBack(){

 

         public void doInSession(CompassSession session) {

           session.save(a);

        }

      });

   }

接口的定义就是有一个doInSession的方法,接受一个CompassSession的对象就可以了,这种设计思想是非常好的一个设计思想,在以后的实际应用中是很常用的,因此,我还是很喜欢这样的思想的,毕竟我是怎么也想不到的,真是佩服这样的大侠们。因此,在使用Compass的时候就可以使用其提供的那个CompassTeplate类了,使用这个类的时候就非常的简单了,比如下面的代码:      CompassTemplate ct = new CompassTemplate(compass);

      ct.create(a);当然如果针对是查询操作,因为存在返回值的情况,因此稍微有点复杂,但是比起以前的做法还是简单了很多的。

   至此为止关于全文检索的知识也就全部总结完了,这里设计的知识非常的多,尤其是Lucene和Compass框架的使用,在以后的开发中可能Compass还是比较常用的,因此有了Lucene的思想,学习Compass也就相对来说比较简单了。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多