首页 > Web开发 > 详细

lucene搜索对象实例

时间:2016-04-10 02:06:49      阅读:315      评论:0      收藏:0      [点我收藏+]

Lucene的搜索对象


一、前期准备

在前面我们提到了,Lucene使用IndexSearcher进行搜索,Lucene作为一个开源的搜索工具包,为开发人员提供了丰富的查询方法,在本节中,我们将讨论不同类型的查询对象和方法。

为了方便看效果,先新建一个类,将我们给定的数据建立索引存放在内存里面

/**
 * 
 * 类名: LuceneQueryAll.java 
 * 包: com.travelsky.pss.react.cn.lucene.query 
 * 描述: TODO 
 * @author tanjie 
 * 创建时间: 2015-11-5 下午12:44:31 
 * @version V1.2.0
 */
public class LuceneQueryAll {
    private Directory directory;
    private IndexReader reader;
    private String[] moneys = { "100", "200", "300", "400", "500", "600" };
    private String[] emails = { "aa@travelsky.com", "bb@travelsky.com",
            "cc@travelsky.com", "dd@travelsky.com", "ee@travelsky.com",
            "ff@travelsky.com" };
    private String[] contents = { "welcome to chongqing",
            "hello boy, I like pingpeng ball", "my name is cc I like game",
            "I like hehe" , "I like football and I like basketball too",
            "I like haha" };
    private String[] names = { "zhangsan", "lisi", "tom", "jetty", "mike",
            "jake" };

    public LuceneQueryAll() { 
         //索引存储在内存中
        directory = new RAMDirectory();
        index();
    }

    /**
     * 
     * @author tanjie
     * 创建时间:  2015-11-5 下午1:01:19
     * 描述: 在内存中简历索引
     */
    public void index() {
        IndexWriter writer = null;
        try {
            writer = new IndexWriter(directory, new IndexWriterConfig(
                    Version.LUCENE_4_9,
                    new StandardAnalyzer(Version.LUCENE_4_9)));
            writer.deleteAll();
            Document doc = null;
            for (int i = 0; i < ids.length; i++) {
                doc = new Document();
                doc.add(new TextField("money", moneys[i], Field.Store.YES));
                doc.add(new TextField("email", emails[i], Field.Store.YES));
                //为了便于观察,我们将内容也存储
                doc.add(new TextField("content", contents[i], Field.Store.YES));
                doc.add(new TextField("name", names[i], Field.Store.YES));
                writer.addDocument(doc);
            }
            writer.commit();
        } catch (CorruptIndexException e) {
            e.printStackTrace();
        } catch (LockObtainFailedException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (writer != null) {
                    writer.close();
                }
            } catch (CorruptIndexException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

   /**
     * 
     * @author tanjie
     * 创建时间:  2015-11-5 下午1:02:12
     * 描述: TODO
     * @return IndexSearcher
     */
   public IndexSearcher getSearcher() {
      try {
           if (reader == null) {
                reader = DirectoryReader.open(directory);
          }
            return new IndexSearcher(reader);
          } catch (CorruptIndexException e) {
            e.printStackTrace();
          } catch (IOException e) {
            e.printStackTrace();
          }
     return null;
   }
}

二、Lucene各个查询对象介绍

2.1 精确查询之TermQuery

TermQuery 是Lucene提供的最基本的一个查询类,从它的构造函数中,我们可以看到它接收的是一个Term对象。Term是一个词条,所以TermQuery是按 照词条进行查询的,词条我们可以将其理解为某个字段的名称,也就是我们要精确搜索到某一个域里面存在某个词条的文档时,TermQuery就起作用了

下面的测试类,我们要精确搜索在域money里面,有200元钱的文档,获得其详细信息。


/**
  * 
  * @author tanjie* 创建时间:  2015-11-5 下午12:16:46
  * 描述: 精确查找
  * @param field 查找的域
  * @param name 查找的词
  * @param num 最多显示多少个
  */
public void searchByTerm(String field, String name, int num) {
   try {
        IndexSearcher searcher = getSearcher();
        Query query = new TermQuery(new Term(field, name));
        TopDocs tds = searcher.search(query, num);
        System.out.println("一共查询了:" + tds.totalHits + "条记录");
        for (final ScoreDoc sd : tds.scoreDocs) {
            Document doc = searcher.doc(sd.doc);
           System.out.println("我有:" + doc.get("money") + "块,名字为" + doc.get("name")
                        + ",邮箱为[" + doc.get("email") + "] ");
        }
     } catch (CorruptIndexException e) {
            e.printStackTrace();
     } catch (IOException e) {
            e.printStackTrace();
     }
}

@Test
public void testSearchByTerm() {
    LuceneQueryAll luceneQueryAll = new LuceneQueryAll();
    luceneQueryAll.searchByTerm("money", "200", 10);
}

运行上面的测试类,运行结果如下:

一共查询了:1条记录
我有:200块,名字为:lisi,邮箱为[bb@travelsky.com] 

2.2使用特定的分析器搜索QueryParser

我们知道,当我们简单的在百度输入一个关键字,然 后点击搜索就可以获得大量的和你搜索的内容相关的文档了,因为搜索引擎帮你做了很多事,而在Lucene中,这项工作就交给了QueryParser类来 完成,QueryParser实际上就是一个解析用户输入的工具,它通过扫描用户输入的字符串然后将其转为一个内部的Query对象。

下面的测试类,我们通过制定搜索的域,解析输入的关键字,来进行搜索。


/**
  * 
  * @author tanjie
  * 创建时间:  2015-11-5 下午12:24:08
  * 描述: 根据特定的分析器搜索
  * @param field 查询域
  * @param keyword 搜索关键字
  * @param num 最多显示多少条
 */
public void searchByQueryParse(String field,String keyword, int num) {
    try {
         IndexSearcher searcher = getSearcher();
         QueryParser queryParser = new QueryParser(Version.LUCENE_4_9, field,
                new StandardAnalyzer(Version.LUCENE_4_9));
         Query query = queryParser.parse(keyword);
         TopDocs tds = searcher.search(query, num);
         System.out.println("一共查询了:" + tds.totalHits +"条记录");
         for (final ScoreDoc sd : tds.scoreDocs) {
                Document doc = searcher.doc(sd.doc);
                System.out.println("我有:" + doc.get("money") + "块,名字为" + doc.get("name")
                        + ",邮箱为[" + doc.get("email") + "] ");
         }
       } catch (CorruptIndexException e) {
            e.printStackTrace();
       } catch (IOException e) {
            e.printStackTrace();
       } catch (ParseException e) {
            e.printStackTrace();
       }
}

@Test
public void testQueryParser() {
    LuceneQueryAll luceneQueryAll = new LuceneQueryAll();
    luceneQueryAll.searchByQueryParse("name","zhangsan", 10);
}

运行上面的测试类,运行结果如下:

一共查询了:1条记录
我有100块,名字为:zhangsan,邮箱为[aa@travelsky.com]-->

2.3 按“与或”搜索BooleanQuery

BooleanQuery其实是多个Query的组 合,我们有时候在搜索的时候,需要结合多个搜索条件,而BooleanQuery则是将多个Query对象添加进来,每个Query由用户指定不同的逻辑 关系,而且,一个BoolenQuery同时也可以嵌套在另一个BooleanQuery里面。

下面的测试类表示我们要搜索索引里面名字不为张三,且内容可以出现game对应的文档。


/**
  * 
  * @author tanjie
  * 创建时间:  2015-11-5 下午12:34:56
  * 描述: 与或 查询
  * @param num 最多显示多少条
  */
public void searchByBoolean(int num) {
  try {
        IndexSearcher searcher = getSearcher();
        BooleanQuery query = new BooleanQuery();
        /*
         * BooleanQuery可以连接多个子查询 ,Occur.MUST表示必须出现,
             Occur.SHOULD表示可以出现,Occur.MUSE_NOT表示不能出现
          */
        query.add(new TermQuery(new Term("name", "zhangsan")),
                    Occur.MUST_NOT);
        query.add(new TermQuery(new Term("content", "game")), Occur.SHOULD);
        TopDocs tds = searcher.search(query, num);
        System.out.println("一共查询了:" + tds.totalHits + "条记录");
        for (final ScoreDoc sd : tds.scoreDocs) {
            Document doc = searcher.doc(sd.doc);
            System.out.println("我有" + doc.get("money") + "块,名字为:" + doc.get("name")
                        + ",邮箱为[" + doc.get("email") + "] " + ",内容为: " +  "[" + doc.get("content") + "]");
        }
    } catch (CorruptIndexException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

@Test
public void testSearchByBoolean() {
    LuceneQueryAll luceneQueryAll = new LuceneQueryAll();
    luceneQueryAll.searchByBoolean(10);
}

运行上面的测试类,运行结果如下:

一共查询了:3条记录
我有400块,名字为jetty,邮箱为[dd@travelsky.com],内容为: [I like football game]
我有200块,名字为lisi, 邮箱为[bb@travelsky.com],内容为: [hello boy, I like pingpeng ball game]
我有300块,名字为john, 邮箱为[cc@travelsky.com] ,内容为: [my name is cc I like game]

2.4 前缀搜索PrefixQuery

PrefixQuery就是使用前缀来进行查找的。通常情况下,首先定义一个词条Term。该词条包含要查找的字段名以及关键字的前缀,然后通过该词条构造一个PrefixQuery对象,就可以进行前缀查找了。


/**
 * 
 * @author tanjie
 * 创建时间:  2015-11-5 下午12:48:36
 * 描述: 根据前缀搜索
 * @param field 搜索的域
 * @param value 搜索的值
 * @param num  最多显示多少条记录
 * void
 */
public void searchByPrefix(String field, String value, int num) {
    try {
        IndexSearcher searcher = getSearcher();
        Query query = new PrefixQuery(new Term(field, value));
        TopDocs tds = searcher.search(query, num);
        System.out.println("一共查询了:" + tds.totalHits + "条记录");
        for (final ScoreDoc sd : tds.scoreDocs) {
            Document doc = searcher.doc(sd.doc);
            System.out.println("我有" + doc.get("money") + "块,名字为:" + doc.get("name")
                        + ",邮箱为[" + doc.get("email") + "] " + ",内容为: " +  "[" + doc.get("content") + "]");
        }
    } catch (CorruptIndexException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}


@Test
public void testSearchByPrefix() {
    LuceneQueryAll luceneQueryAll = new LuceneQueryAll();
     //搜索域为email,前缀为aa的结果,最多显示10条
    luceneQueryAll.searchByPrefix("email","aa", 10);
}

运行上面的测试类,运行结果如下:

一共查询了:1条记录
我有100块,名字为:zhangsan,邮箱为[aa@travelsky.com],内容为: [welcome to chongqing game,I like eat]

2.5 模糊查询FuzzyQuery

FuzzyQuery是Lucene提供的一个用来模糊匹配的Query,比如,在我们的索引里面。域name对应的词中有,mike,make,mikes等,我们可以通过FuzzyQuery 来实现只搜索mike即搜索出与之相近的文档。


/**
 * 
 * @author tanjie
 * 创建时间:  2015-11-5 下午12:58:58
 * 描述: 模糊查询FuzzyQuery
 * @param num
 */
public void searchByFuzzy(int num) {
    try {
        IndexSearcher searcher = getSearcher();
        //查询名字为mikes的,但是实际上索引里面域name里面真正的名字是mike
        FuzzyQuery query = new FuzzyQuery(new Term("name", "mikes"),1);
        TopDocs tds = searcher.search(query, num);
        System.out.println("一共查询了:" + tds.totalHits + "条记录");
        for (final ScoreDoc sd : tds.scoreDocs) {
            Document doc = searcher.doc(sd.doc);
            System.out.println("我有" + doc.get("money") + "块,名字为:" + doc.get("name")
                        + ",邮箱为[" + doc.get("email") + "] " + ",内容为: " +  "[" + doc.get("content") + "]");
        }
    } catch (CorruptIndexException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

    @Test
public void testSearchByFuzzy() {
    LuceneQueryAll luceneQueryAll = new LuceneQueryAll();
    luceneQueryAll.searchByFuzzy(10);
}

运行上面的测试类,运行结果如下:

一共查询了:1条记录
我有500块,名字为:mike,邮箱为[ee@travelsky.com] ,内容为: [I like football and I like basketball too]

Lucene还提供了很多的查询对象,比如通配符查询,根据范围查询,这里不依依介绍,想深入了解的,可以看Lucene的官网文档,都有相应的demo。

lucene搜索对象实例

原文:http://090508tanjie.iteye.com/blog/2289712

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!