[Lucene]核心类和概念介绍

先上一个使用Lucene读写文件的DEMO

import java.io.IOException;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;
public class IndexAndSearchExample {public static void main(String[] args) throws IOException {// 创建内存中的索引目录Directory indexDir = new RAMDirectory();// 创建分词器。Analyzer analyzer = new StandardAnalyzer();// 配置IndexWriterIndexWriterConfig config = new IndexWriterConfig(analyzer);//IndexWriter构建时会检查目录下是否有索引,没有则写入新索引。如果有则只向索引添加内容IndexWriter writer = new IndexWriter(indexDir, config);// 创建文档Document doc1 = new Document();doc1.add(new TextField("title", "Lucene in Action", Field.Store.YES));doc1.add(new TextField("description", "Lucene is a powerful search library", Field.Store.YES));writer.addDocument(doc1);Document doc2 = new Document();doc2.add(new TextField("title", "Java Development with Ant", Field.Store.YES));doc2.add(new TextField("description", "Learn how to use Ant to build, test, and deploy your Java applications", Field.Store.YES));writer.addDocument(doc2);// 提交文档,IndexWriter会向Directory提交写入变化。IndexWriter还可以继续使用writer.commit();//关闭IndexWriter.也会触发提交文档writer.close();// 创建IndexSearcher,能够对指定Directory搜索DirectoryReader reader = DirectoryReader.open(indexDir);IndexSearcher searcher = new IndexSearcher(reader);// 构建查询Query query = new TermQuery(new Term("title", "lucene"));// 执行查询ScoreDoc[] hits = searcher.search(query, 10).scoreDocs;// 遍历结果for (ScoreDoc hit : hits) {Document result = searcher.doc(hit.doc);System.out.println(result.get("title") + " : " + result.get("description"));}// 关闭IndexReaderreader.close();}
}


Directory

索引文件所在目录,存储一批文件的抽象层。提供文件增删查改的方法。

Analyzer

分词器。用于将text分割成更小的term(词汇单元),还可能会执行大小写转换、无用词删除等操作

Field

document组成部分,有name,type,value属性。值可以是string、number、byte[]。包含以下实例化选项

  • stored 是否需要存储域的真实值(source),例如网页正文就不需要存储真实值,聊天记录就需要 。对应索引文件中的stored_field
  • tokenized 代表是否做分词,在lucene中只有TextField这一个字段需要做分词。
  • termVector: term vector保存了一个文档内所有的term的相关信息,包括Term值、出现次数(frequencies)以及位置(positions)等,是一个per-document inverted index,提供了根据docid来查找该文档内所有term信息的能力。对于长度较小的字段不建议开启term verctor,因为只需要重新做一遍分词即可拿到term信息,而针对长度较长或者分词代价较大的字段,则建议开启term vector。Term vector的用途主要有两个,一是关键词高亮(知道offset才能高亮),二是做文档间的相似度匹配(more-like-this)。
  • omitNorms: Norms是normalization的缩写,lucene允许每个文档的每个字段都存储一个normalization factor,是和搜索时的相关性计算有关的一个系数。Norms的存储只占一个字节,但是每个文档的每个字段都会独立存储一份,且Norms数据会全部加载到内存。所以若开启了Norms,会消耗额外的存储空间和内存。但若关闭了Norms,则无法做index-time boosting
  • IndexOptions 控制字段的多少信息会被索引。有以下信息:doc, term frequencues, positions, offsets. 如果为none则不索引。存储的词频、出现次数、位置和偏移量信息,用于执行查询和计算文档得分等操作。
  • docValuesType 正向索引(docid到field的一个列存),大大优化了sorting、faceting或aggregation的效率。DocValues是一个强schema的存储结构,开启DocValues的字段必须拥有严格一致的类型,不同的doc的该字段的类型必须相同 。对应索引文件中的doc_values
  • dimension:Lucene支持多维数据的索引,采取特殊的索引来优化对多维数据的查询

Document

索引和查询的单元,由一些field组成

doc id

Lucene的Index通过DocId来唯一标识一个Doc.

  • DocId实际上并不在Index内唯一,而是Segment内唯一,Lucene这么做主要是为了做写入和压缩优化。那既然在Segment内才唯一,又是怎么做到在Index级别来唯一标识一个Doc呢?方案很简单,基于segment内值的范围给他一个附加值,例如两个有5个doc的segment,第二个segment的附加值是5,第二个segment中的doc 3的外部值为8
  • DocId在Segment内唯一,取值从0开始递增。但不代表DocId取值一定是连续的,如果有Doc被删除,那可能会存在空洞。
  • 一个文档对应的DocId可能会发生变化,主要是发生在Segment合并时。

IndexWriter

IndexWriter创建并维护索引。同一时间一个索引只能有一个IndexWriter,该功能通过文件锁实现。
每个更改索引的方法都会返回一个序列号,它表示应用每个更改的有效顺序。 commit 还返回一个序列号,描述哪些更改在提交点中,哪些不在。序列号是暂时的(不会以任何方式保存到索引中)并且仅在单个 IndexWriter 实例中有效。
这些数据修改缓存在内存中并周期性的flush到Directory,自上次flush之后当有足够的doc时将触发flush。flush只是将缓存的数据修改移动到索引,但这些数据修改对Reader不可见,直到调用commit或close。
DWPT线程的数量等于调用IndexWriter的写接口的线程数量

IndexWriter.addDocument

将doc加到索引中。这个方法周期性调用flush和segment merge。

  • 多线程并发调用IndexWriter的写接口,在IndexWriter内部具体请求会由DocumentsWriter来执行。DocumentsWriter内部在处理请求之前,会先根据当前执行操作的Thread来分配DocumentsWriterPerThread。
  • 每个线程在其独立的DocumentsWriterPerThread空间内部进行数据处理,包括分词、相关性计算、索引构建等。每个DocumentsWriterPerThread空间都包含一个In-memory buffer,这个buffer最终会flush成不同的独立的segment文件。
  • 数据处理完毕后,在DocumentsWriter层面执行一些后续动作,例如触发FlushPolicy的判定等。

IndexWriter.optimize()

IndexWriter.optimize()可以进行段合并,可以提升搜索速度,合并期间会消耗大量的CPU和IO资源,并且需要额外的磁盘空间保存新的段,调用commit之前旧的段不会被删除,结束之后占用的磁盘空间比之前要少

IndexWriter.flush()

将所有内存中的segments移动到Directory(有FSDirectory,RAMDirectory),不会等待数据真正写入磁盘(对于linux数据会先写到filesystem cache),但不会进行commit,所以数据不可读。

IndexWriter.commit()

IndexWriter.commit()将提交所有pending的更改(add doc\delete doc\ segment merge)到索引,并同步相关的索引文件(会等待文件真正的持久存储而不是写到filesystem cache就返回),所以这些更改对IndexReader来说是可见的。并且更新内容不会因为系统崩溃而丢失。
换句话说,commit会触发flush并使数据可读

IndexWriter.getReader

flush内存中缓存的doc,创建并返回一个包含这些doc的Reader,涵盖对索引的所有已提交(commited)和未提交(un-commited)的更改,这些更改可读并且不需要调用commit。
请注意,这在功能(结果而不是过程)上等同于调用 {flush} 然后打开一个新的reader。但是这种方法的周转时间应该更快,因为它避免了可能代价高昂的commit。
这提供了near real-time search,无需commit就能使数据可以搜索。叫做近实时的原因是——没有保证当对IndexWriter进行更改后你能多快的获得新的Reader。

IndexReader

提供接口访问某一时间点的索引。直到新的IndexReader被打开前,所有通过IndexWriter完成的更改都不会可见。同一时间一个索引可以有多个reader

DirectoryReader.openIfChanged

获取一个新Reader,包含最新的数据。
DirectoryReader.openIfChanged底层会调用IndexWriter.getReader,该方法会使IndexWriter立马刷新出新的段内容(flush),而不是等到内存缓冲区满。

IndexSearcher

通过IndexReader实现查询。出于性能的原因,如果索引未更改应该在多个查询之间共享IndexSearcher,而不是创建新的索引。如果索引更改了,需要调用DirectoryReader.openIfChanged并创建新的IndexSearcher。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/670837.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

互联网加竞赛 基于深度学习的动物识别 - 卷积神经网络 机器视觉 图像识别

文章目录 0 前言1 背景2 算法原理2.1 动物识别方法概况2.2 常用的网络模型2.2.1 B-CNN2.2.2 SSD 3 SSD动物目标检测流程4 实现效果5 部分相关代码5.1 数据预处理5.2 构建卷积神经网络5.3 tensorflow计算图可视化5.4 网络模型训练5.5 对猫狗图像进行2分类 6 最后 0 前言 &#…

大型语言模型(LLM)的优势、劣势和风险

最近关于大型语言模型的奇迹()已经说了很多LLMs。这些荣誉大多是当之无愧的。让 ChatGPT 描述广义相对论,你会得到一个非常好(且准确)的答案。然而,归根结底,ChatGPT 仍然是一个盲目执行其指令集…

进程控制(Linux)

进程控制 一、进程创建1. 再识fork2. 写时拷贝 二、进程终止前言——查看进程退出码1. 退出情况正常运行,结果不正确异常退出 2. 退出码strerror和errno系统中设置的错误码信息perror异常信息 3. 退出方法exit和_exit 三、进程等待1. 解决等待的三个问题2. 系统调用…

银行数据仓库体系实践(17)--数据应用之营销分析

营销是每个银行业务部门重要的工作任务,银行产品市场竞争激烈,没有好的营销体系是不可能有立足之地,特别是随着互联网金融发展,金融脱媒”已越来越普遍,数字化营销方兴未艾,银行的营销体系近些年也不断发展&#xff0c…

Go语言教学(一)起源

目录 一.Go语言来源 二.Go语言应用 一.Go语言来源 Go语言,又称Golang,是Google公司于2009年11月正式对外公开的一门编程语言。它是一门静态强类型、编译型的语言,其语法与C相近,但在功能上有所改进和增加,如内存安全…

【精选】java继承进阶,子类继承父类(内存图、内存分析工具)

🍬 博主介绍👨‍🎓 博主介绍:大家好,我是 hacker-routing ,很高兴认识大家~ ✨主攻领域:【渗透领域】【应急响应】 【python】 【VulnHub靶场复现】【面试分析】 🎉点赞➕评论➕收藏…

ftrace工具学习笔记

ftrace是一个功能强大的Linux内核跟踪工具,可用于分析内核的行为和性能问题。它可以用来收集各种内核跟踪数据,如函数调用、内存分配、中断处理等。以下是ftrace的一些主要特点和用法: ftrace是内核自带的跟踪工具,因此无需安装。…

FRP内网穿透如何避免SSH暴力破解(二)——指定地区允许访问

背景 上篇文章说到,出现了试图反复通过FRP的隧道,建立外网端口到内网服务器TCP链路的机器人,同时试图暴力破解ssh。这些连接造成了流量的浪费和不必要的通信开销。考虑到服务器使用者主要分布在A、B、C地区和国家,我打算对上一篇…

ELAdmin 前端启动

开发工具 官方指导的是使用WebStorm,但是本人后端开发一枚,最终还是继续使用了 idea,主打一个能用就行。 idea正式版激活方式: 访问这个查找可用链接:https://3.jetbra.in/进入任意一个能用的里面,顶部提…

消息中间件之RocketMQ源码分析(六)

Consumer消费方式 RocketMQ的消费方式包含Pull和Push两种 Pull方式。 用户主动Pull消息,自主管理位点,可以灵活地掌控消费进度和消费速度,适合流计算、消费特别耗时等特殊的消费场景。 缺点也显而易见,需要从代码层面精准地控制…

vue3+ts+vite搭建步骤

vue3 ts vite搭建步骤如下: 1,首先确保你的机器上已经安装了 Node.js 和 npm。你可以通过在终端运行 node -v 和 npm -v 来检查是否已经安装。 2,安装 Vite。在你的终端运行以下命令 npm install -g create-vite3,使用 Vite 创…

docker部署自己的网站wordpress

目录 安装 1.创建目录 2.创建并启动mysql 3.创建并启动wordpress 使用 1.设置语言 2.设置基础信息 3.首页 安装 1.创建目录 mkdir -p /opt/wordpress/{db,data} 2.创建并启动mysql docker run -d --name my_mysql --restart always -e MYSQL_ROOT_PASSWORD123456 -e …

深度学习本科课程 实验1 Pytorch基本操作

一、Pytorch基本操作考察 1.1 任务内容 使用 𝐓𝐞𝐧𝐬𝐨𝐫 初始化一个 𝟏𝟑 的矩阵 𝑴 和一个 𝟐𝟏 的矩阵 𝑵,对两矩阵…

home work day5

第四章 堆与拷贝构造函数 一 、程序阅读题 1、给出下面程序输出结果。 #include <iostream.h> class example {int a; public: example(int b5){ab;} void print(){aa1;cout <<a<<"";} void print()const {cout<<a<<endl;} …

flutter使用qr_code_scanner扫描二维码

qr_code_scanner仓库地址&#xff1a;qr_code_scanner | Flutter Package 需要添加android和ios的相机权限和本地相册权限&#xff1a; android中添加权限: 在android\app\build.gradle中修改&#xff1a;minSdkVersion 20 并且在android/app/src/main/AndroidManifest.xml中…

【力扣】Z字形变换,模拟+直接构造

Z字形变换原题地址 方法一&#xff1a;利用二维矩阵模拟 对于特殊情况&#xff0c;z字形变换后只有一行或只有一列&#xff0c;则变换后的字符串和原字符串相同。 对于一般情况&#xff0c;我们可以考虑按照题目要求&#xff0c;把字符串按照Z字形存储到二维数组中&#xff…

【linux】git和gdb调试工具

在linux下提交代码同步到gitee 1.创建一个新的仓库&#xff08;演示步骤&#xff09; 2.init 这两个步骤用于识别提交代码的身份&#xff0c;一个你的名字&#xff0c;一个你的邮箱 开启本地仓库 克隆本地仓库成功 我们将这个仓库拷到了111目录底下. 我们发现少了一个.gitig…

测试python模块每个模块耗时

1.安装包 pip install snakeviz2. 运行测试 # 模块测试运行命令 PYTHONPATH$PWD python -m cProfile -o profile.stats_v2 new_core/schemes/cost_bom/bom_server.py #可视化运行的结果 python -m snakeviz profile.stats_v2 --server -H 0.0.0.0 -p 80813. 参数解释 cProfil…

最小覆盖子串[困难]

优质博文&#xff1a;IT-BLOG-CN 一、题目 给你一个字符串s、一个字符串t。返回s中涵盖t所有字符的最小子串。如果s中不存在涵盖t所有字符的子串&#xff0c;则返回空字符串"" 。 对于t中重复字符&#xff0c;我们寻找的子字符串中该字符数量必须不少于t中该字符数量…

使用Nginx搭建旁路服务器获取客户端真实IP

一、前言 在实际业务开发过程中&#xff0c;很多时候有记录客户端真实IP的需求&#xff0c;但是从客户端发送的请求往往会经过很多代理服务器&#xff0c;导致后端服务获取的IP为代理以后的IP&#xff0c;不具有业务含义。为了解决这个问题&#xff0c;可以搭建一个旁路服务器…