Lucene深入浅出

Posted 分享录

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Lucene深入浅出相关的知识,希望对你有一定的参考价值。

一、Lucene的基础简介

1.Lucene的由来

  • 原始的搜索技术

  • 如果用户比较少而且数据库的数据量比较小,那么这种方式实现搜索功能在企业中是比较常见的。

  • 现在的搜索技术

Lucene深入浅出

  • 使用 Lucene 的 API 的来操作服务器上的索引库,可解决数据库压力和速度的问题。

2.Lucene是什么?

  • Lucene 是一种全文检索技术,常见的搜索框架 Solr 或 ElasticSearch 都是基于Lucene进行扩展开发的。所谓全文检索就是计算机索引程序通过扫描文件中的每一个词,对每一个词建立一个索引,指明该词在文件中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户。

  • Lucene 是apache软件基金会4 jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎、部分文本分析引擎。

  • Lucene 的创始人是 Doug Cutting,其目的是为软件开发人员提供一个简单易用的工具包,以方便在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。

  • Lucene 提供了一个简单却强大的应用程序接口,能够做全文索引和搜寻, 在Java开发环境里 Lucene 是一个成熟且免费的开放源代码工具。

  • Lucene 并不是现成的搜索引擎产品,但可以用来制作搜索引擎产品。

3.常见的查询算法

  • 顺序扫描法

    所谓顺序扫描,就是在要找内容的文件中进行全文件扫描,如果此文档包含要查找的内容,则此文档为我们要找的文件,否则接着看下一个文件,直到扫描完所有的文件。

    • 优点查询精准率高

    • 缺点:查询速度会随着数据量的增大而变慢

    • 场景:数据库中的Like关键字查询、文本编辑器的Ctrl+F查找功能

  • 倒排索引

    Lucene采用的就是倒排索引

    所谓倒排索引,就是查询前会先将查询的内容提取出来组成文档(正文),然后对文档进行切分词组成索引(目录),这个过程中索引可以去掉重复的词,索引和文档有关联关系,查询的时候先查询索引,通过索引找文档的这个过程叫做全文检索。

    • 优点:查询精准率高、查询速度快

    • 缺点:索引文件会占用额外的磁盘空间

    • 场景:进行海量数据查询

4.基本的应用场景

  • 用于站内搜索,例如:淘宝、京东

  • 用于垂直领域搜索,例如:招聘网

  • 作为搜索引擎,例如:百度、Google

二、两大核心流程

Lucene深入浅出

1.构建索引库的流程

Lucene深入浅出

  • 获取内容

    从互联网上、数据库、文件系统中等获取需要搜索的原始信息,这个过程就是信息采集,采集数据的目的是为了对原始内容进行索引。

    • 对于互联网上的网页,可以使用工具将网页抓取到本地生成html文件

    • 对于数据库中的数据,可以直接连接数据库读取表中的数据

    • 对于文件系统中的某个文件,可以通过I/O操作读取文件的内容

  • 创建文档

    将获取的原始内容创建成文档(Document),文档是由一个一个的键值对组成,相当于数据库中的一条数据。

Lucene深入浅出

  • 分析文档

    对文档中的内容进行分析,利用分词器进行拆分。

  • 建立索引

    将拆分后的词整合在一起,建立成一个索引库,相当于一个目录。

    Lucene深入浅出

2.搜索索引库中数据的流程

  • 创建查询

    用户输入查询关键字执行搜索之前需要先构建一个查询对象,查询对象中可以指定要查询关键字、要搜索的Field文档域等,查询对象会生成具体的查询语法。

  • 执行搜索

    根据查询语法在倒排索引库中分别找出对应搜索词的索引,从而找到索引所对应的文档。

  • 渲染结果

    将搜索到的结果从索引库返回给系统,由系统将结果渲染到界面。

三、核心的底层原理

1.索引库的存储结构

Lucene深入浅出

  • 索引(Index)

    • 一个目录一个索引,在Lucene中一个索引库是放在一个文件夹中的。

  • 段(Segment)

    • 一个索引由多个段组成,多个段可以合并以减少读取内容时候的磁盘IO。

    • Lucene 中的数据写入会先写内存的一个Buffer,当Buffer内数据到一定量后会被flush成一个 Segment,每个Segment有自己独立的索引,可独立被查询,但数据永远不能被更改。

    • Segment 中写入的文档不可被修改,但可被删除,删除的方式也不是在文件内部原地更改,而是会由另外一个文件保存需要被删除的文档的DocID,保证数据文件不可被修改。

    • 索引的查询需要对多个 Segment 进行查询并对结果进行合并,还需要处理被删除的文档,为了对查询进行优化,Lucene会有策略对多个Segment进行合并。

  • 文档(Document)

    • 文档是索引的基本单位,不同的文档是保存在不同的段中的,一个段可以包含多篇文档。

    • 新添加的文档是单独保存在一个新生成的段中,随着段的合并,不同的文档合并到同一个段中。

  • 域(Field)

    • 域是文档的基本单位,由键值对组成。

    • 文档包含不同类型的信息,可以分开索引保存在不同的域里,不同域的索引方式可以不同。

2.索引库中的物理文件

Lucene深入浅出

名称 扩展名 描述
Segments File segments_n 保存了一个提交点(a commit point)的信息
Lock File write.lock 防止多个IndexWriter同时写到一份索引文件中
Segment Info .si 保存了索引段的元数据信息
Compound File .cfs,.cfe 一个可选的虚拟文件,把所有索引信息都存储到复合索 引文件中
Fields .fnm 保存fields的相关信息
Field Index .fdx 保存指向field data的指针
Field Data .fdt 文档存储的字段的值
Term Dictionary tim term词典,存储term信息
Term Index .tip 到Term Dictionary的索引
Frequencies .doc 由包含每个term以及频率的docs列表组成
Positions .pos 存储出现在索引中的term的位置信息
Payloads .pay 存储额外的per-position元数据信息,例如字符偏移和 用户payloads
Norms nvd,.nvm nvm文件保存索引字段加权因子的元数据,.nvd文件保 存索引字段加权数据
Per-Document Values .dvd,.dvm .dvm文件保存索引文档评分因子的元数据,.dvd文件保 存索引文档评分数据
Term Vector Index tvx 将偏移存储到文档数据文件中
Term Vector Documents .tvd 包含有term vectors的每个文档信息
Term Vector Fields .tvf 字段级别有关term vectors的信息
Live Documents .liv 哪些是有效文件的信息
Point values dii,.dim 保留索引点,如果有的话

3.索引库中词典的构建

指的是索引库中对关键字目录进行构建

存储结构 描述
跳跃表 占用内存小,且可调,但是对模糊查询支持不好
排序列表 使用二分法查找,不平衡
字典树 查询效率跟字符串长度有关,但只适合英文词典
哈希表 性能高,内存消耗大,几乎是原始数据的三倍
双数组字典树 适合做中文词典,内存占用小,很多分词工具均采用此种算法
FST 一种有限状态转移机,Lucene 4有开源实现,并大量使用
B树/B+树 磁盘索引,更新方便,但检索速度慢,多用于数据库
  • 跳跃表结构

    单链表

Lucene深入浅出

  • 跳跃表

Lucene深入浅出

    • 优点:结构简单、跳跃间隔、级数可控

    • 缺点:模糊查询支持不好

  • FST结构

Lucene深入浅出

    • 优点内存占用率低、查询快、能够支持模糊查询

    • 缺点:结构复杂、输入要求有序、更新不易

三、Field域详解

Field是文档中的域,包括Field名和Field值两部分,一个文档可以包括多个Field。

Document是Field 的一个承载体,Field名即是索引内容的字段名称,Field值即是索引的内容。

1.Field域的三大属性

  • 是否分词

    • 进行分词,即将Field值进行分词,分词的目的是为了索引。

      一般进行分词的都是用户可进行搜索的内容

    • 不进行分词。

      一般不进行分词的都是一些不可分割的内容

  • 是否索引

    • 进行索引,将Field分词后的词存储到索引域,索引的目的是为了搜索。

      一般进行索引的都是作为用户查询条件的内容

    • 不进行索引。

      一般不进行索引的都是不作为用户查询条件的内容

  • 是否存储

    • 进行存储,将Field值存储在文档中,存储的目的是为了展示。

      一般进行存储的都是需要展示的内容

    • 不进行存储。

      一般不进行存储的都是不需要展示的内容

2.Field域的常见类型

Field类型 Java类型 是否分词 是否索引 是否存储 描述
StringField String N Y Y或N 此类型会将整个字符串存储在索引中
FloatPoint Float Y Y N 对Float类型进行分词和索引
DoublePoint Double Y Y N 对Double类型进行分词和索引
LongPoint Long Y Y N 对Long类型进行分词和索引
IntPoint Integer Y Y N 对Integer类型进行分词和索引
StoredField 多种类型 N N Y 对值进行存储
TextField String或流 Y Y Y或N 对值进行分词、索引
NumericDocValuesField 数值类型 - - - 配合排序使用

四、索引库的维护

1.添加索引

一般用于在索引库初始化或数据库新增数据的时候

void addIndex() throws Exception{ // 创建Document文档对象集合 Document document = new Document(); document.add(new StringField("id", "000000001", Field.Store.YES)); document.add(new TextField("字段名", "字段值", Field.Store.YES));
// 创建分词器对象 Analyzer analyzer = new StandardAnalyzer();
// 创建IndexWriterConfig对象 IndexWriterConfig indexConfig = new IndexWriterConfig(analyzer);
// 创建Directory对象,用于声明索引库的存储位置 Directory directory = FSDirectory.open(Paths.get("索引库的位置"));
// 创建IndexWriter对象并把Document写入到索引库中 IndexWriter writer = new IndexWriter(directory, indexConfig); writer.addDocument(document);
// 释放资源 writer.close();}

2.修改索引

一般用于在数据库修改数据的时候

void updIndex() throws Exception{ // 创建Document文档对象集合 Document document = new Document(); document.add(new StringField("id", "000000001", Field.Store.YES)); document.add(new TextField("字段名", "新的字段值", Field.Store.YES));
// 创建分词器对象 Analyzer analyzer = new StandardAnalyzer();
// 创建IndexWriterConfig对象 IndexWriterConfig indexConfig = new IndexWriterConfig(analyzer);
// 创建Directory对象,用于声明索引库的存储位置 Directory directory = FSDirectory.open(Paths.get("索引库的位置"));
// 创建IndexWriter对象并把Document写入到索引库中 IndexWriter writer = new IndexWriter(directory, indexConfig); writer.updateDocument(new Term("id", "000000001"), document);
// 释放资源 writer.close();}

3.删除索引

一般用于在数据库删除数据的时候

void delIndex() throws Exception{ // 创建分词器对象 Analyzer analyzer = new StandardAnalyzer();
// 创建IndexWriterConfig对象 IndexWriterConfig indexConfig = new IndexWriterConfig(analyzer);
// 创建Directory对象,用于声明索引库的存储位置 Directory directory = FSDirectory.open(Paths.get("索引库的位置"));
// 创建IndexWriter对象并把Document写入到索引库中 IndexWriter writer = new IndexWriter(directory, indexConfig); writer.deleteDocuments(new Term("id", "000000001"),...);// 根据条件删除 writer.deleteDocuments(new Query(),...);// 根据条件删除 writer.deleteAll();// 删除全部
// 释放资源 writer.close();}

五、什么是分词器?

1.基础概述

分词器就是将要索引的内容进行分词解析,分词的目的就是生成索引目录,方便搜索使用。

  • 分词将采集到的数据Document对象中的Field值按照指定的分词规则进行拆分。

  • 过滤将拆分后的词进行过滤,比如:去掉重复的词、大写转为小写、标点符号的去除、去掉停用词等。

    [注]:停用词就是在搜索引擎解析时会被自动忽略的字或词,比如:语气助词、副词、介词、连接词等。

2.使用时机

  • 索引库建立时使用

    在创建索引库或对索引库进行新增、修改时使用,主要是为了对文档内容进行解析,生成索引目录。

  • 搜索内容时使用

    在用户搜索时使用,主要是为了对用户输入的关键词进行解析,便于搜索到想要的结果。

3.Lucene原生的分词器

Lucene自带的常见分词器

  • StandardAnalyzer

    可以对用英文进行分词,对中文是单字分词也就是一个字就认为是一个词

    // 核心源码protected TokenStreamComponents createComponents(String fieldName) { final StandardTokenizer src = new StandardTokenizer(); src.setMaxTokenLength(this.maxTokenLength); TokenStream tok = new LowerCaseFilter(src); TokenStream tok = new StopFilter(tok, this.stopwords); return new TokenStreamComponents(src, tok) { protected void setReader(Reader reader) { src.setMaxTokenLength(StandardAnalyzer.this.maxTokenLength); super.setReader(reader); } };}
  • WhitespaceAnalyzer

    仅仅是去掉了空格,没有其他任何操作,不支持中文分词

    // 核心源码protected TokenStreamComponents createComponents(String fieldName) { return new TokenStreamComponents(new WhitespaceTokenizer());}
  • SimpleAnalyzer

    将除了字母以外的所有符号全部去掉,字母转化为小写,不支持中文分词

    // 核心源码protected TokenStreamComponents createComponents(String fieldName) { Tokenizer tokenizer = new LetterTokenizer(); return new TokenStreamComponents(tokenizer, new LowerCaseFilter(tokenizer));}
  • CJKAnalyzer

    去掉空格、标点符号,字母转化为小写,对中日韩文字进行二分法分词

    // 核心源码protected TokenStreamComponents createComponents(String fieldName) { Tokenizer source = new StandardTokenizer(); TokenStream result = new CJKWidthFilter(source); TokenStream result = new LowerCaseFilter(result); TokenStream result = new CJKBigramFilter(result); return new TokenStreamComponents(source, new StopFilter(result, this.stopwords));}
  • CustomAnalyzer

    自定义分词规则

    protected TokenStreamComponents createComponents(String fieldName) { Tokenizer tk = this.tokenizer.create(this.attributeFactory(fieldName)); TokenStream ts = tk; TokenFilterFactory[] var4 = this.tokenFilters; int var5 = var4.length;
    for(int var6 = 0; var6 < var5; ++var6) { TokenFilterFactory filter = var4[var6]; ts = filter.create((TokenStream)ts); }
    return new TokenStreamComponents(tk, (TokenStream)ts);}

4.常见的中文分词器

第三方提供的分词器

  • paoding

    庖丁解牛最新版在 https://code.google.com/p/paoding/ 中最多支持Lucene 3.0,且最新提交的代码在 2008-06-03,在svn中最新也是2010年提交,已经过时,不予考虑。

  • mmseg4j

    最新版已从 https://code.google.com/p/mmseg4j/ 移至 https://github.com/chenlb/mmseg4j-solr,支持Lucene 4.10,且在github中最新提交代码是2014年6月,从09年~14年一 共有:18个版本,也就是一年几乎有3个大小版本,有较大的活跃度,用了mmseg算法。

  • ansj_seg

    最新版本在 https://github.com/NLPchina/ansj_seg tags仅有1.1版本,从2012年到 2014年更新了大小6次,但是作者本人在2014年10月10日说明:“可能我以后没有精力来维护 ansj_seg了”,现在由”nlp_china”管理。2014年11月有更新。并未说明是否支持Lucene,是一个 由CRF(条件随机场)算法所做的分词算法。

    imdict-chinese-analyzer

    最新版在 https://code.google.com/p/imdict-chinese-analyzer/ , 最新更新也在2009年5月,下载源码,不支持Lucene 4.10 。是利用HMM(隐马尔科夫链)算法。

    Jcseg

    最新版本在http://git.oschina.net/lionsoul/jcseg,支持Lucene 4.10,作者有较高的活跃度。利用mmseg算法。

    IK-analyze

    最新版在https://code.google.com/p/ik-analyzer/上,支持Lucene 4.10从2006年 12月推出1.0版开始, IKAnalyzer已经推出了4个大版本。最初,它是以开源项目Luence为应用主 体的,结合词典分词和文法分析算法的中文分词组件。从3.0版本开 始,IK发展为面向Java的公用 分词组件,独立于Lucene项目,同时提供了对Lucene的默认优化实现。在2012版本中,IK实现了 简单的分词 歧义排除算法,标志着IK分词器从单纯的词典分词向模拟语义分词衍化。但是也就是 2012年12月后没有在更新。

// 核心源码protected TokenStreamComponents createComponents(String fieldName) { Tokenizer _IKTokenizer = new IKTokenizer(this.useSmart()); return new TokenStreamComponents(_IKTokenizer);}

六、基础Java API的使用

1.创建模拟数据

创建数据库 lucene ,执行 tb_sku.sql 文件,模拟商品数据。

Lucene深入浅出

2.项目环境的搭建

  • 添加相关依赖

    <!--Spring Boot相关依赖--><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>
    <!--Lucene相关依赖--><dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-core</artifactId> <version>8.4.0</version></dependency><dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-analyzers-common</artifactId> <version>8.4.0</version></dependency><dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-queryparser</artifactId> <version>8.4.0</version></dependency><dependency> <groupId>com.github.magese</groupId> <artifactId>ik-analyzer</artifactId> <version>8.4.0</version></dependency>
    <!--数据库相关依赖--><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version></dependency><dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.12</version></dependency><dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.2.0</version></dependency>
    <!--其它依赖--><dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version></dependency><dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.73</version></dependency>
  • 添加配置

server.port=8080server.servlet.context-path=/spring.application.name=lucene
spring.datasource.type=com.alibaba.druid.pool.DruidDataSourcespring.datasource.driver-class-name=com.mysql.jdbc.Driverspring.datasource.url=jdbc:mysql://localhost:3306/lucene spring.datasource.username=rootspring.datasource.password=root
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImplmybatis-plus.type-aliases-package=com.jhy.lucene.pojo
  • 分词器的配置

    中文分词器配置,解压 ik-analyzer 的源码,将配置文件拷贝到项目的 resources 目录下 (可选)

Lucene深入浅出

  • 创建实体类

    @TableName("tb_sku")public class Sku {
    //商品主键id private String id; //商品名称 private String name; //价格 private Integer price; //库存数量 private Integer num; //图片 private String image; //分类名称 private String categoryName; //品牌名称 private String brandName; //规格 private String spec; //销量 private Integer saleNum;}
  • 生成索引库过程

void createFlow() throws Exception{ // 获取数据 List<Sku> skus = skuDao.selectList(null);
// 创建Document文档对象集合 List<Document> documents = new ArrayList<>(); for (Sku sku : skus) { Document document = new Document(); document.add(new TextField("id", sku.getId(), Field.Store.YES)); document.add(new TextField("name", sku.getName(), Field.Store.YES)); document.add(new TextField("price", sku.getPrice().toString(), Field.Store.YES)); document.add(new TextField("image", sku.getImage(), Field.Store.YES)); document.add(new TextField("categoryName", sku.getCategoryName(), Field.Store.YES)); document.add(new TextField("brandName", sku.getBrandName(), Field.Store.YES));
documents.add(document); }
// 创建分词器对象 Analyzer analyzer = new StandardAnalyzer();
// 创建IndexWriterConfig对象 IndexWriterConfig indexConfig = new IndexWriterConfig(analyzer);
// 创建Directory对象,用于声明索引库的存储位置 Directory directory = FSDirectory.open(Paths.get("索引库的位置"));
// 创建IndexWriter对象并把Document写入到索引库中 IndexWriter writer = new IndexWriter(directory, indexConfig); for (Document document : documents) { writer.addDocument(document); }
// 释放资源 writer.close();}

3.测试使用

  • 查看生成的索引库

    Lucene深入浅出

  • 使用Luke工具查看内容

Lucene深入浅出

  • Lucene深入浅出

    Lucene深入浅出

    Lucene深入浅出

  • 使用Luke工具进行搜索

    Lucene深入浅出

  • 使用代码进行搜索

void QueryFlow() throws Exception{ // 创建Query搜索对象(参数一:默认查询的Field域名称、参数二:使用的分词器) Analyzer analyzer = new StandardAnalyzer(); QueryParser queryParser = new QueryParser("name", analyzer); Query query = queryParser.parse("华为手机");
// 创建Directory对象,指明索引库的位置 Directory directory = FSDirectory.open(Paths.get("索引库的位置"));
// 创建IndexReader索引读取对象 IndexReader reader = DirectoryReader.open(directory);
// 创建IndexSearcher索引搜索对象 IndexSearcher searcher = new IndexSearcher(reader);
// 执行搜索,获取返回结果集TopDocs TopDocs docs = searcher.search(query, 10);
// 解析结果集 System.out.println("结果集总数:" + docs.totalHits); ScoreDoc[] scoreDocs = docs.scoreDocs; for (ScoreDoc scoreDoc : scoreDocs) { Document document = searcher.doc(scoreDoc.doc); System.out.println("id:" + document.get("id")); System.out.println("name:" + document.get("name")); System.out.println("price:" + document.get("price")); System.out.println("image:" + document.get("image")); System.out.println("categoryName:" + document.get("categoryName")); System.out.println("brandName:" + document.get("brandName")); }
// 释放资源 reader.close();}

Lucene深入浅出

Lucene深入浅出

七、Lucene的高级使用

1.文本搜索

void Query() throws Exception{ Analyzer analyzer = new IKAnalyzer();  //参数一:默认查询的Field域名称 //参数二:使用的分词器类型 QueryParser queryParser = new QueryParser("name", analyzer); Query query = queryParser.parse("华为手机"); // 使用默认Field域名称 Query query = queryParser.parse("name:华为手机"); // 使用指定Field域名称 Query query = queryParser.parse("description:华为手机"); // 使用指定Field域名称
// 创建Directory对象,指明索引库的位置 Directory directory = FSDirectory.open(Paths.get("索引库的位置")); // 创建IndexReader索引读取对象 IndexReader reader = DirectoryReader.open(directory); // 创建IndexSearcher索引搜索对象 IndexSearcher searcher = new IndexSearcher(reader); // 执行搜索,获取返回结果集TopDocs TopDocs docs = searcher.search(query);}

2.多域搜索

void Query() throws Exception{ Analyzer analyzer = new IKAnalyzer();  //参数一:默认查询的Field域名称集合 //参数二:使用的分词器类型 String[] fields = {"name", "description"}; QueryParser queryParser = new MultiFieldQueryParser(fields, analyzer); Query query = queryParser.parse("华为手机"); 
// 创建Directory对象,指明索引库的位置 Directory directory = FSDirectory.open(Paths.get("索引库的位置")); // 创建IndexReader索引读取对象 IndexReader reader = DirectoryReader.open(directory); // 创建IndexSearcher索引搜索对象 IndexSearcher searcher = new IndexSearcher(reader); // 执行搜索,获取返回结果集TopDocs TopDocs docs = searcher.search(query);}

3.范围搜索

void Query() throws Exception{ Analyzer analyzer = new IKAnalyzer();  //参数一:查询的Field域名称 //参数二:最小值 //参数三:最大值 Query query = FloatPoint.newRangeQuery("price", 100, 1000);
// 创建Directory对象,指明索引库的位置 Directory directory = FSDirectory.open(Paths.get("索引库的位置")); // 创建IndexReader索引读取对象 IndexReader reader = DirectoryReader.open(directory); // 创建IndexSearcher索引搜索对象 IndexSearcher searcher = new IndexSearcher(reader); // 执行搜索,获取返回结果集TopDocs TopDocs docs = searcher.search(query);}

4.组合搜索

void Query() throws Exception{ Analyzer analyzer = new IKAnalyzer();  // 条件1 Query query1 = FloatPoint.newRangeQuery("price", 100, 1000); // 条件2 QueryParser queryParser = new QueryParser("name", analyzer); Query query2 = queryParser.parse("华为手机"); // 条件组合 // BooleanClause.Occur.MUST 必须 相当于and, 并且 // BooleanClause.Occur.MUST_NOT 不必须 相当于not, 取非 // BooleanClause.Occur.SHOULD 应该 相当于or, 或者 BooleanQuery.Builder builder = new BooleanQuery.Builder(); builder.add(query1, BooleanClause.Occur.MUST); builder.add(query2, BooleanClause.Occur.MUST); Query query = builder.build();  // 创建Directory对象,指明索引库的位置 Directory directory = FSDirectory.open(Paths.get("索引库的位置")); // 创建IndexReader索引读取对象 IndexReader reader = DirectoryReader.open(directory); // 创建IndexSearcher索引搜索对象 IndexSearcher searcher = new IndexSearcher(reader); // 执行搜索,获取返回结果集TopDocs TopDocs docs = searcher.search(query);}

------------END-----------

更多原创文章请扫描上面(微信内长按可识别二维码访问我的个人网站(https://www.xubingtao.cn),或者打开我的微信小程序: 可以评论以及在线客服反馈问题,其他平台小程序APP请访问:https://www.xubingtao.cn/?p=1675祝大家生活愉快!

以上是关于Lucene深入浅出的主要内容,如果未能解决你的问题,请参考以下文章

深入理解 Lucene 的 flush 过程

ES 工程师需要深入理解的 Lucene Flush 过程

ElasticSearch 2 (10) - 在ElasticSearch之下(深入理解Shard和Lucene Index)

搜索引擎1

Javalucene4.0学习心得

Lucene初探之索引过程分析