Lucene-Query的使用及其索引库的维护

1 Lucene的Query的使用

Lucene是使用Query对象执行查询的, 由Query对象生成查询的语法. 如bookName:java, 表示搜索bookName域中包含java的文档数据.

1.1 Query对象的两种创建方法

1.1.1 使用Query子类对象

1.1.1.1 常用的Query子类对象

子类对象 说明
TermQuery 不使用分析器, 对关键词做精确匹配搜索. 如:订单编号、身份证号
NumericRangeQuery 数字范围查询, 比如: 图书价格大于80, 小于100
BooleanQuery 布尔查询, 实现组合条件查询. 组合关系有: 1. MUST与MUST: 表示“与”, 即“交集” 2. MUST与MUST NOT: 包含前者, 排除后者 3. MUST NOT与MUST NOT: 没有意义 4. SHOULD与MUST: 表示MUST, SHOULD失去意义 5. SHOULD与MUST NOT: 等于MUST与MUST NOT 6. SHOULD与SHOULD表示“或”, 即“并集”

1.1.1.2 常用的Query子类对象使用

1.1.1.2.1 使用TermQuery
  • 需求: 查询图书名称中包含java的图书.
/**
 * 搜索索引(封装搜索方法)
 */
private void seracher(Query query) throws Exception {
    // 打印查询语法
    System.out.println("查询语法: " + query);

    // 1.创建索引库目录位置对象(Directory), 指定索引库的位置
    Directory directory = FSDirectory.open(new File("/Users/healchow/Documents/index"));

    // 2.创建索引读取对象(IndexReader), 用于读取索引
    IndexReader reader = DirectoryReader.open(directory);

    // 3.创建索引搜索对象(IndexSearcher), 用于执行搜索
    IndexSearcher searcher = new IndexSearcher(reader);  

    // 4. 使用IndexSearcher对象执行搜索, 返回搜索结果集TopDocs
    // 参数一:使用的查询对象, 参数二:指定要返回的搜索结果排序后的前n个
    TopDocs topDocs = searcher.search(query, 10);

    // 5. 处理结果集
    // 5.1 打印实际查询到的结果数量
    System.out.println("实际查询到的结果数量: " + topDocs.totalHits);
    // 5.2 获取搜索的结果数组
    // ScoreDoc中有文档的id及其评分
    ScoreDoc[] scoreDocs = topDocs.scoreDocs;

    for (ScoreDoc scoreDoc : scoreDocs) {
        System.out.println("= = = = = = = = = = = = = = = = = = =");
        // 获取文档的id和评分
        int docId = scoreDoc.doc;
        float score = scoreDoc.score;
        System.out.println("文档id= " + docId + " , 评分= " + score);

        // 根据文档Id, 查询文档数据 -- 相当于关系数据库中根据主键Id查询数据
        Document doc = searcher.doc(docId);
        System.out.println("图书Id: " + doc.get("bookId"));
        System.out.println("图书名称: " + doc.get("bookName"));
        System.out.println("图书价格: " + doc.get("bookPrice"));
        System.out.println("图书图片: " + doc.get("bookPic"));
        System.out.println("图书描述: " + doc.get("bookDesc"));
    }

    // 6. 关闭资源
    reader.close();
}
  • 测试使用TermQuery:
/**
 * 测试使用TermQuery: 需求: 查询图书名称中包含java的图书
 */
@Test
public void testTermQuery() throws Exception {
    //1. 创建TermQuery对象
    TermQuery termQuery = new TermQuery(new Term("bookName", "java"));
    // 2.执行搜索
    this.seracher(termQuery);
}

1.1.1.2.2 使用NumericRangeQuery
  • 需求: 查询图书价格在80-100之间的图书(不包含80和100):
/**
 * 测试使用NumericRangeQuery: 需求: 查询图书价格在80-100之间的图书
 */
@Test
public void testNumericRangeQuery() throws Exception{
    // 1.创建NumericRangeQuery对象, 参数说明:
    // field: 搜索的域; min: 范围最小值; max: 范围最大值
    // minInclusive: 是否包含最小值(左边界); maxInclusive: 是否包含最大值(右边界)
    NumericRangeQuery numQuery = NumericRangeQuery.newFloatRange("bookPrice", 80f, 100f, false, false);

    // 2.执行搜索
    this.seracher(numQuery);
}

  • 测试包含80和100:
// 测试包含80和100

NumericRangeQuery numQuery = NumericRangeQuery.newFloatRange("bookPrice", 80f, 100f, true, true);

1.1.1.2.3 使用BooleanQuery
  • 需求: 查询图书名称中包含Lucene, 并且价格在80-100之间的图书.
/**
 * 测试使用BooleanQuery: 需求: 查询图书名称中包含Lucene, 且价格在80-100之间的图书
 */
@Test
public void testBooleanQuery() throws Exception {
    // 1.创建查询条件
    // 1.1.创建查询条件一
    TermQuery query1 = new TermQuery(new Term("bookName", "lucene"));

    // 1.2.创建查询条件二
    NumericRangeQuery query2 = NumericRangeQuery.newFloatRange("bookPrice", 80f, 100f, true, true);
    // 2.创建组合查询条件
    BooleanQuery bq = new BooleanQuery();
    // add方法: 添加组合的查询条件
    // query参数: 查询条件对象
    // occur参数: 组合条件
    bq.add(query1, Occur.MUST);
    bq.add(query2, Occur.MUST);

    // 3.执行搜索
   this.seracher(bq);
}

查询语法中, "+"表示并且条件, "-"表示不包含后面的条件:

1.1.2 使用QueryParser

说明: 使用QueryParser对象解析查询表达式, 实例化Query对象.

1.1.2.1 QueryParse表达式语法

  • 关键词基本查询: 域名+":"+关键词, 比如: bookname:lucene
  • 范围查询: 域名+":"+[最小值 TO 最大值], 比如: price:[80 TO 100]. 需要注意QueryParser不支持数字范围查询, 仅适用于字符串范围查询. 如果有数字范围查询需求, 请使用NumericRangeQuery.
  • 组合查询:
条件表示符 符号说明 符号表示
Occur.MUST 搜索条件必须满足, 相当于AND +
Occur.SHOULD 搜索条件可选, 相当于OR 空格
Occur.MUST_NOT 搜索条件不能满足, 相当于NOT非 -

1.1.3 使用QueryParser

需求: 查询图书名称中包含java, 并且图书名称中包含"Lucene"的图书.

/**
 * 测试使用QueryParser: 需求: 查询图书名称中包含Lucene, 且包含java的图书
 */
@Test
public void testQueryParser() throws Exception {
    // 1.创建查询对象
    // 1.1.创建分析器对象
    Analyzer analyzer = new IKAnalyzer();
    // 1.2.创建查询解析器对象
    QueryParser qp = new QueryParser("bookName", analyzer);
    // 1.3.使用QueryParser解析查询表达式
    Query query = qp.parse("bookName:java AND bookName:lucene");

    // 2.执行搜索
    this.seracher(query);
}

注意: 使用QueryParser, 表达式中的组合关键字AND/OR/NOT必须要大写. 设置了默认搜索域后, 若查询的域没有改变, 则可不写.

2 Lucene索引库的维护

数据保存在关系型数据库中, 需要实现增、删、改、查操作; 索引保存在索引库中, 也需要实现增、删、改、查操作.

2.1 增加索引

参考 Lucene-入门程序及Java API的简单使用 中的内容:

2.2 删除索引

2.2.1 根据Term删除索引

  1. 创建分析器对象(Analyzer), 用于分词;
  2. 创建索引配置对象(IndexWriterConfig), 用于配置Lucene;
  3. 创建索引库目录对象(Directory), 用于指定索引库的位置;
  4. 创建索引写入对象(IndexWriter), 用于操作索引;
  5. 创建删除条件对象(Term);
  6. 使用IndexWriter对象, 执行删除;
  7. 释放资源.
/**
 * 根据Term删除索引
 */
@Test
public void deleteIndexByTerm() throws IOException {
    // 1.创建分析器对象(Analyzer), 用于分词
    Analyzer analyzer = new IKAnalyzer(); 

    // 2.创建索引配置对象(IndexWriterConfig), 用于配置Lucene
    IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_4_10_4, analyzer);

    // 3.创建索引库目录对象(Directory), 用于指定索引库的位置
    Directory directory = FSDirectory.open(new File("/Users/healchow/Documents/index"));

    // 4.创建索引写入对象(IndexWriter), 用于操作索引
    IndexWriter writer = new IndexWriter(directory, iwc);

    // 5.创建删除条件对象(Term)
    // 删除图书名称域中, 包含"java"的索引
    // delete from table where name="java"
    // 参数一: 删除的域的名称, 参数二: 删除的条件值
    Term term = new Term("bookName", "java"); 

    // 6.使用IndexWriter对象, 执行删除
    // 可变参数, 能传多个term
    writer.deleteDocuments(term);

   // 7.释放资源
    writer.close();
}

根据Term执行删除操作(indexWriter.deleteDocuments(term))时, 要求对应的Field不能分词且只能是一个词, 且这个Field必须索引过, Lucene将先去搜索, 然后将所有满足条件的记录删除(伪删除, 做了".del"标记) -- 最好定义一个唯一标识来做删除操作.

是否删除索引, 需要分情况讨论: 我们知道, Lucene是以段(segment)来组织索引内容的, 通过Term执行删除操作(indexWriter.deleteDocuments(term))时, 若索引段中仍包含符合条件的文档对象的其他分词的索引, 就会保留整个索引数据(若采取更新操作, 则会降低性能), 如果没有, 则也将删除索引数据:

查看删除了的文档的编号:

2.2.2 删除全部索引(慎用)

  1. 创建分析器对象(Analyzer), 用于分词;
  2. 创建索引配置对象(IndexWriterConfig), 用于配置Lucene;
  3. 创建索引库目录对象(Directory), 指定索引库位置;
  4. 创建索引写入对象(IndexWriter), 用于操作索引库;
  5. 使用IndexWriter对象, 执行删除;
  6. 释放资源.
/**
* 删除全部索引
*/
@Test
public void deleteAllIndex() throws IOException {
   // 1.创建分析器对象(Analyzer), 用于分词
   Analyzer analyzer = new IKAnalyzer();

   // 2.创建索引配置对象(IndexWriterConfig), 用于配置Lucene
   IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_4_10_4, analyzer);

   // 3.创建索引库目录对象(Directory), 用于指定索引库的位置
   Directory directory = FSDirectory.open(new File("/Users/healchow/Documents/index"));

   // 4.创建索引写入对象(IndexWriter), 用于操作索引
   IndexWriter writer = new IndexWriter(directory, iwc);

   // 5.使用IndexWriter对象, 执行删除
   writer.deleteAll();

   // 6.释放资源
  writer.close();
}

删除后的索引结果:

删除全部索引, 将文档域的数据, 索引域的数据都删除.

类似于关系型数据库的Truncate删除: 完全删除数据, 包括存储结构, 因而更快速.

2.3 更新索引

Lucene是根据Term对象更新索引: 先根据Term执行查询, 查询到则执行更新, 查询不到则执行添加索引.

  1. 创建分析器对象(Analyzer), 用于分词;
  2. 创建索引配置对象(IndexWriterConfig), 用于配置Lucene;
  3. 创建索引库目录对象(Directory), 用于指定索引库的位置;
  4. 创建索引写入对象(IndexWriter), 用于操作索引库;
  5. 创建文档对象(Document);
  6. 创建Term对象;
  7. 使用IndexWriter对象, 执行更新;
  8. 释放资源.
/**
 * 更新索引
 */
@Test
public void updateIndexByTerm() throws IOException{
    // 1.创建分析器对象(Analyzer), 用于分词
    Analyzer analyzer = new IKAnalyzer();

    // 2.创建索引配置对象(IndexWriterConfig), 用于配置Lucene
    IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_4_10_4, analyzer);   

    // 3.创建索引库目录对象(Directory), 用于指定索引库的位置
    Directory directory = FSDirectory.open(new File("/Users/healchow/Documents/index"));   

    // 4.创建索引写入对象(IndexWriter), 用于操作索引
    IndexWriter writer = new IndexWriter(directory, iwc);

    // 5.创建文档对象(Document)
    Document doc = new Document();
    doc.add(new TextField("id", "1234", Store.YES));
    // doc.add(new TextField("name", "MyBatis and SpringMVC", Store.YES));
    doc.add(new TextField("name", "MyBatis and Struts2", Store.YES)); 

    // 6.创建Term对象
    Term term = new Term("name", "SpringMVC"); 

    // 7.使用IndexWriter对象, 执行更新
    writer.updateDocument(term, doc);

    // 8.释放资源
    writer.close();
}

第一次执行, 由于没有查找到对应的索引, 故执行添加功能, 结果如图(不区分大小写):

第二次执行时, 由于索引库中已有"name"="SpringMVC"的内容, 故执行更新操作: 将整个TextField的内容:"MyBatis and Struts2"添加到索引库中, 并与上次的结果合并, 结果如下图示:

若第二次执行时更改了Term中name域的条件值(索引中没有对应的), 将继续执行添加功能: 将整个TextField中的内容添加到索引中.

版权声明

作者: ma_shoufeng(马瘦风)

出处: 博客园 马瘦风的博客

您的支持是对博主的极大鼓励, 感谢您的阅读.

本文版权归博主所有, 欢迎转载, 但未经博主同意必须保留此段声明, 且在文章页面明显位置给出原文链接, 否则博主保留追究法律责任的权利.

原文地址:https://www.cnblogs.com/shoufeng/p/9398964.html

时间: 2024-10-10 07:59:14

Lucene-Query的使用及其索引库的维护的相关文章

全文检索之lucene的优化篇--创建索引库

在上一篇HelloWorld的基础上,建立一个directory的包,添加一个DirectoryTest的测试类,用来根据指定的索引目录创建目录存放指引. DirectoryTest类中的代码如下,基本上就是在HelloWorld的基础上改改就可以了. 里面一共三个方法,testDirectory(),测试创建索引库;testDirectoryFSAndRAM(),结合方法1的两种创建方式,优化;testDirectoryOptimize(),在方法2个基础上,研究索引的优化创建,减少创建的索引

维护solr索引库

一 2)solrcore    一个solr下可以有多个solrcore,每个solrcore就是一个独立的索引库3)solrconfig.xml    lib:配置solr的扩展包的位置,不指定路径的话就是collection1/lib目录,可以自动加载.如果没有需要手动创建    dataDir:索引文件保存的位置.如果不指定默认是Collection1/data目录.如果没有会自动生成    requestHandler:请求的url及对应的处理器的配置4)添加solrcore    1.

JAVAEE——Solr:安装及配置、后台管理索引库、 使用SolrJ管理索引库、仿京东的电商搜索案例实现

1 学习回顾 1. Lucene  是Apache开源的全文检索的工具包 创建索引 查询索引 2. 遇到问题? 文件名 及文件内容  顺序扫描法  全文检索 3. 什么是全文检索? 这种先创建索引 再对索引进行搜索的过程叫全文检索 4. 索引是什么? 非结构数据中提取一个数据.并重新组合的过程叫索引 5. Lucene实现 6. 入门程序 磁盘文件为原始文件 创建索引 第一步:获取文件 第二步:创建文档对象 第三步:创建分析器 第四步:保存索引及文档到索引库 搜索索引 第一步:用户接口(百度)

lucene内存索引库、分词器

内存索引库 特点 在内存中开辟一块空间,专门为索引库存放.这样有以下几个特征: 1)    因为索引库在内存中,所以访问速度更快. 2)    在程序退出时,索引库中的文件也相应的消失了. 3)    如果索引库比较大,必须得保证足够多的内存空间. 编码 在cn.hqu.directory 下新建:DirectoryTest /** * 1.能不能设置很多个索引库 *    可以设置很多个索引库 * 2.索引库能不能合并起来 *    如果是内存索引库 *      Directory ramD

2.Lucene3.6.2包介绍,第一个Lucene案例介绍,查看索引信息的工具lukeall介绍,Luke查看的索引库内容,索引查找过程

 1  Lucen目录介绍 2  lucene-core-3.6.2.jar是lucene开发核心jar包 contrib  目录存放,包含一些扩展jar包 3  案例 建立第一个Lucene项目:lucene3_day1 (1)需要先将数据转换成为Document对象,每一个数据信息转换成为Field(String name, String value, Field.Store store, Field.Indexindex) (2)指定索引库位置Directorydirectory =

第一个lucene程序,把一个信息写入到索引库中、根据关键词把对象从索引库中提取出来、lucene读写过程分析

新建一个Java Project :LunceneTest 准备lucene的jar包,要加入的jar包至少有: 1)lucene-core-3.1.0.jar     (核心包) 2) lucene-analyzers-3.1.0.jar    (分词器) 3) lucene-highlighter-3.1.0.jar    (高亮器) 4) lucene-memory-3.1.0.jar       (高亮器) 新建实体类:Article, 属性:id,title,content; gett

Lucene系列:(5)LuceneUtils之索引库优化

1.什么是索引库 索引库是Lucene的重要的存储结构,它包括二部份:原始记录表,词汇表 原始记录表:存放的是原始记录信息,Lucene为存入的内容分配一个唯一的编号 词汇表:存放的是经过分词器拆分出来的词汇和该词汇在原始记录表中的编号 2.为什么要将索引库进行优化 在默认情况下,向索引库中增加一个Document对象时,索引库自动会添加一个扩展名叫*.cfs的二进制压缩文件,如果向索引库中存Document对象过多,那么*.cfs也会不断增加,同时索引库的容量也会不断增加,影响索引库的大小.

lucene索引库的增删改查操作

1. 索引库的操作 保持数据库与索引库的同步 说明:在一个系统中,如果索引功能存在,那么数据库和索引库应该是同时存在的.这个时候需要保证索引库的数据和数据库中的数据保持一致性.可以在对数据库进行增.删.改操作的同时对索引库也进行相应的操作.这样就可以保证数据库与索引库的一致性. 工具类DocumentUtils 在对索引库进行操作时,增.删.改过程要把一个JavaBean封装成Document,而查询的过程是要把一个Document转化成JavaBean.在进行维护的工作中,要反复进行这样的操作

Lucene建立索引库

问题?Lucene如何建立索引库,lucene所需要的jar包是那些  , lucene如何使用索引库,lucene的核心原理 一.Lucene是什么? 全文检索只是一个概念,而具体实现有很多框架,lucene是其中的一种方式.本文将以lucene3.0进行开发 官兵与Luncne的jar包可以去官网下载:点击打开链接,不过好像Lucene已经更新到6.1了. 二.建立索引库 1.互联网搜索全文搜索引擎结构图: 2.Lucene的结构图: 说明: (1)在数据库中,数据库中的数据文件存储在磁盘上