Lucene重要特性及应用案例

文章目录

      • Elasticsearch Python 示例
      • Lucene Java 示例
      • Elasticsearch Python 示例进阶:多字段搜索与排序
      • Lucene Java 示例进阶:使用TermQuery进行精确匹配

Lucene底层存储结构:

Lucene作为高性能的全文搜索引擎库,其底层存储结构设计得非常精巧,以支持高效的索引创建和搜索操作。Lucene的核心存储结构主要包括以下几个部分:

  1. 倒排索引(Inverted Index)

    • 这是Lucene最核心的数据结构。在建立索引时,Lucene会将文档中的词汇项作为关键字,文档ID作为值,形成一种“值-键”对调的结构。这样在搜索时,就可以直接根据关键词快速定位到包含该词的所有文档。
    • 倒排索引由多个段(Segment)组成,每个段都是一个独立的倒排列表集合,这样的设计便于索引的更新和删除操作。
    • 每个段还包括词典(Dictionary)、频率文件(Frequency File或Posting List)、位置文件(Position File)等,用于存储词项、文档频率、词在文档中的位置等信息。
  2. 压缩与优化

    • 为了节省空间和提高效率,Lucene会对倒排索引进行多种层次的压缩,包括字典项的编码压缩、posting列表的delta编码等。
    • 在索引过程中还会进行合并(Merge)操作,将多个小段合并成大段,减少文件数量,提升搜索效率。
  3. 存储格式

    • Lucene使用一系列复杂的文件结构来存储索引信息,如.fdt(存储字段值)、.fdx(字段值的偏移量)、.tii/.tis(词典的索引和数据)等。

顺序扫描法的原理:

顺序扫描法(Serial Scanning),也称为线性扫描,是一种基础而直观的文档搜索方法,其工作原理非常直接:

  • 当需要在文档集合中查找包含特定关键词的文档时,顺序扫描法会逐个打开文档,从第一个文档开始,顺序读取每个文档的全部内容。
  • 对于每个文档,系统会检查文档内的每一部分,判断是否包含目标关键词。如果找到了匹配的关键词,则记录下这个文档作为搜索结果的一部分。
  • 这个过程会持续进行,直到所有文档都被检查过为止。

这种方法的优点在于实现简单,不需要预先构建索引,适用于数据量不大且不频繁搜索的场景。然而,缺点也非常明显,即搜索效率极低,特别是当文档数量庞大时,搜索速度会变得非常缓慢,因为每次搜索都需要遍历整个文档集。相比之下,Lucene采用的倒排索引结构极大地提高了搜索效率,特别是在处理大规模数据集时。

Lucene的其他关键组件和特性:

除了上述提到的倒排索引和顺序扫描法外,Lucene还包括一些其他重要组件和特性,这些也是其高效运行的基础:

  1. 分析器(Analyzer)

    • 分析器负责将文本分割成词语(Tokenization),并可进行诸如去除停用词、词干提取等标准化处理。这是索引创建和搜索查询处理的前期步骤,确保了索引和查询的词汇形式一致。
  2. 评分机制(Scoring)

    • Lucene采用了一套复杂的评分算法(如TF-IDF、BM25等)来评估文档与查询的相关度,并据此排序。这使得搜索结果不仅包含匹配的文档,还能按相关性高低排序,提高用户满意度。
  3. 缓存机制(Caching)

    • 为了进一步提升性能,Lucene实现了多级缓存策略,包括字段缓存、段元数据缓存、分数缓存等,减少了对磁盘的访问,加速了频繁查询的响应时间。
  4. 近实时搜索(Near Real-Time Search)

    • Lucene支持近乎实时的索引更新和搜索,意味着新添加或修改的文档可以在很短时间内被索引并可供搜索,大大缩短了信息的可见延迟。
  5. 多字段搜索与过滤

    • Lucene允许在多个字段上同时执行搜索,并且支持复杂的过滤条件,提高了搜索的灵活性和精确度。

与Elasticsearch的关系:
Elasticsearch是基于Lucene构建的分布式全文搜索引擎,它封装了Lucene的复杂性,提供了RESTful API、集群管理、自动扩展、数据分片与复制等高级功能。虽然Elasticsearch在更高层面上操作,但其底层依然依赖于Lucene的索引和搜索机制,包括倒排索引、分析器等核心组件。因此,理解Lucene的工作原理对于深入掌握Elasticsearch的运行机制至关重要。

下面我将分别提供一个使用Elasticsearch的Python代码示例来创建索引和执行一个基本的搜索查询,以及一个使用Lucene的Java代码示例来实现相似的功能。这两个例子都是简化版,用于展示如何在实际项目中应用这两个技术。

Elasticsearch Python 示例

首先,确保已经安装了elasticsearch库。这个例子会展示如何连接到Elasticsearch服务器,创建一个索引,并执行一个简单的搜索查询。

from elasticsearch import Elasticsearch

# 连接Elasticsearch
es = Elasticsearch()

# 定义一个索引名
index_name = "example_index"

# 创建索引(如果不存在)
if not es.indices.exists(index=index_name):
    es.indices.create(index=index_name)

# 准备一条文档数据
doc = {
    "title": "测试文档",
    "content": "这是一个用于测试Elasticsearch搜索功能的文档。",
    "timestamp": "2023-04-01T10:00:00"
}

# 将文档添加到索引中
res = es.index(index=index_name, body=doc)
print(f"Indexed document ID: {res['_id']}")

# 执行搜索
search_query = {
    "query": {
        "match": {
            "content": "测试Elasticsearch"
        }
    }
}
response = es.search(index=index_name, body=search_query)

# 打印搜索结果
for hit in response['hits']['hits']:
    print(hit["_source"])

Lucene Java 示例

Lucene的使用稍微复杂一些,因为它是一个底层库,通常需要更多的手动设置。下面的Java代码示例展示了如何创建一个索引并执行查询。你需要在项目中包含Apache Lucene库。

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.store.RAMDirectory;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;

public class LuceneExample {

    public static void main(String[] args) throws Exception {
        // 创建内存索引目录
        RAMDirectory directory = new RAMDirectory();

        // 分析器
        StandardAnalyzer analyzer = new StandardAnalyzer();

        // 索引配置
        IndexWriterConfig config = new IndexWriterConfig(analyzer);

        // 创建索引写入器
        IndexWriter indexWriter = new IndexWriter(directory, config);

        // 添加文档到索引
        Document doc = new Document();
        doc.add(new TextField("content", "这是一个Lucene搜索的测试文档。", Field.Store.YES));
        indexWriter.addDocument(doc);
        indexWriter.commit();
        indexWriter.close();

        // 搜索
        DirectoryReader ireader = DirectoryReader.open(directory);
        IndexSearcher isearcher = new IndexSearcher(ireader);

        QueryParser parser = new QueryParser("content", analyzer);
        org.apache.lucene.search.Query query = parser.parse("Lucene搜索");

        TopDocs topDocs = isearcher.search(query, 10);
        for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
            Document hitDoc = isearcher.doc(scoreDoc.doc);
            System.out.println(hitDoc.get("content"));
        }

        ireader.close();
    }
}

请注意,这些示例代码假设你已经具备了相应的开发环境和依赖库。在实际应用中,还需要考虑异常处理、资源管理等更多细节。

Elasticsearch Python 示例进阶:多字段搜索与排序

在前一个Elasticsearch的Python示例基础上,我们将扩展功能,实现多字段搜索及按照相关性或自定义字段排序的结果输出。

from elasticsearch import Elasticsearch

es = Elasticsearch()

index_name = "example_index"

# 假设我们要添加一个包含更多字段的文档
doc2 = {
    "title": "深度学习在搜索引擎中的应用",
    "author": "张三",
    "category": "AI技术",
    "content": "本文探讨了深度学习技术在提高搜索结果相关性方面的作用。",
    "publish_date": "2023-04-05T09:00:00",
    "popularity_score": 85
}

es.index(index=index_name, body=doc2)

# 多字段搜索与排序示例
search_query = {
    "query": {
        "multi_match": {
            "query": "搜索技术 深度学习",
            "fields": ["title^2", "content"]  # title字段的权重设为2,表示更相关
        }
    },
    "sort": [
        {"popularity_score": {"order": "desc"}},  # 按popularity_score降序排序
        {"_score": {"order": "desc"}}  # 再按相关性得分降序排序
    ]
}

response = es.search(index=index_name, body=search_query)

for hit in response['hits']['hits']:
    print(f"Title: {hit['_source']['title']}, Popularity Score: {hit['_source']['popularity_score']}")

在这个示例中,我们使用了multi_match查询来同时在多个字段中搜索关键词,并且为不同字段指定了不同的权重,以调整搜索的相关性。此外,我们还通过sort参数指定了结果的排序方式,先按popularity_score降序,再按搜索得分降序,从而实现了更复杂的搜索需求。

Lucene Java 示例进阶:使用TermQuery进行精确匹配

在上一个Lucene Java示例的基础上,我们进一步探索如何使用TermQuery进行精确字段匹配,并展示如何获取文档的特定字段值。

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.store.RAMDirectory;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;

public class LuceneAdvancedExample {

    public static void main(String[] args) throws Exception {
        RAMDirectory directory = new RAMDirectory();
        StandardAnalyzer analyzer = new StandardAnalyzer();
        IndexWriterConfig config = new IndexWriterConfig(analyzer);
        IndexWriter indexWriter = new IndexWriter(directory, config);

        Document doc = new Document();
        doc.add(new TextField("title", "深入理解Lucene索引机制", Field.Store.YES));
        doc.add(new TextField("author", "李四", Field.Store.YES));
        indexWriter.addDocument(doc);
        indexWriter.commit();
        indexWriter.close();

        DirectoryReader ireader = DirectoryReader.open(directory);
        IndexSearcher isearcher = new IndexSearcher(ireader);

        TermQuery query = new TermQuery(new org.apache.lucene.index.Term("author", "李四"));  // 精确匹配author字段
        TopDocs topDocs = isearcher.search(query, 10);

        for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
            Document hitDoc = isearcher.doc(scoreDoc.doc);
            System.out.println("Title: " + hitDoc.get("title") + ", Author: " + hitDoc.get("author"));
        }

        ireader.close();
    }
}

在这个Java示例中,我们不仅向索引中添加了一个额外的字段author,还在搜索时使用了TermQuery来进行精确匹配,仅查找那些author字段值为"李四"的文档。最后,我们从命中文档中获取并打印出titleauthor字段的值,展示了如何在Lucene中检索和处理特定字段信息。

😍😍 大量H5小游戏、微信小游戏、抖音小游戏源码😍😍
😍😍试玩地址: https://www.bojiogame.sg😍😍
😍看上哪一款,需要源码的csdn私信我😍

————————————————

​最后我们放松一下眼睛
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】类和对象(三)构造与析构

文章目录 一、类的6个默认成员函数二、 构造函数干嘛的?语法定义特性综上总结什么是默认构造函数? 三、析构函数干嘛的 ?语法定义析构顺序 一、类的6个默认成员函数 如果一个类中什么成员都没有,简称为空类。空类中并不是真的什么…

不懂索引,简历上都不敢写自己熟悉SQL优化

大家好,我是考哥。 今天给大家带来MySQL索引相关核心知识。对MySQL索引的理解甚至比你掌握SQL优化还重要,索引是优化SQL的前提和基础,我们一步步来先打好地基。 当MySQL表数据量不大时,缺少索引对查询性能的影响不会太大&#x…

在react项目中让webpack使用mock数据

1. 创建react项目 使用 create-react-app 创建项目 npx create-react-app react-mock 执行 eject 命令 npm run eject 删除 package.json 文件中的 eslintConfig 选项 2. 安装依赖包 npm i path-to-regexp fast-glob chokidar axios 3. 创建中间件 在 config 文件夹中创…

Android【SDK】 SDK是如何开发的,怎么打包aar包

文章目录 一、Android SDK开发示例工程二、Android SDK的开发三、打包aar包四、Android SDK的使用 一、Android SDK开发示例工程 本教程工程Git链接:https://gitcode.com/xiaohuihui1400/AndroidSdkExample/overview 二、Android SDK的开发 新建项目,…

Linux驱动开发笔记(九)IIC子系统及其驱动

文章目录 前言一、IIC驱动框架二、总线驱动2.1 iic总线的运行机制2.2 重要数据结构2.2.1 i2c_driver结构体2.2.2 i2c总线结构体 2.3 匹配规则 三、设备树的修改四、设备驱动的编写4.1 相关API函数4.1.1 i2c_add_adapter( )4.1.2 i2c_register_driver( )4.1.3 i2c_transfer( )4.…

MDK-ARM 编译后 MAP 文件分析

本文配合 STM32 堆栈空间分布 食用更佳! 一图胜千言。。。

【LLM之NL2SQL】DAIL-SQL论文阅读笔记

研究背景 该研究旨在提供一个全面、系统的评估框架,用于评估基于大型语言模型(LLM)的Text-to-SQL技术。特别强调了不同的提示工程策略的有效性和效率,以及开源LLM的可行性。研究的重点是评估在零样本和少样本场景下的不同问题表示…

ICC2如何写DCG需要的floorplan信息

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 DCG需要哪些floorplan信息呢? 1)fixed属性的port和mem / ip / io 2)boundary信息 3)电源域形状 前两条都可以写到def里,电源域需要用脚本处理,这里分享一下脚本。 set_fixed_objects [ge…

# 消息中间件 RocketMQ 高级功能和源码分析(七)

消息中间件 RocketMQ 高级功能和源码分析(七) 一、 消息中间件 RocketMQ 源码分析:消息存储核心类介绍 1、消息存储在 store 模块中。消息存储核心类 DefaultMessageStore.java 2、消息存储核心类介绍 private final MessageStoreConfig me…

react18 实现具名插槽

效果预览 技术要点 当父组件给子组件传递的 JSX 超过一个标签时,子组件接收到的 children 是一个数组,通过解析数组中各 JSX 的属性 slot ,即可实现具名插槽的分发! 代码实现 Father.jsx import Child from "./Child";…

DNF安卓分离仅是开始:游戏厂商积极布局自有渠道,市场变革在即

毫无征兆,DNF手游今天突然宣布从各大安卓平台下架。 《地下城与勇士:起源》运营团队于6月19日发布声明,指出因合约到期,游戏将不再上架部分安卓平台的应用商店。然而,这一事件并非完全无迹可循。 早在2021年初,华为游…

ROM以及ROM与RAM对比

1.ROM ROM最原始的定义是“只读存储器”,一旦写入原始信息则不能更改。所以ROM通常用来存放固定不变的程序、常数和汉字字库,甚至用于操作系统的固化。它与随机存储器可共同作为主存的一部分,统一构成主存的地址域。 现在已经发展出了很多R…

商超便利店收银系统源码推荐

细节决定成败,无论是做什么事情都要注重细节,让我们来看看关于商超便利店陈列的“细节”有哪些需要注意的地方。 首先要注意商品不要摆太高,放在适当位置即可! 商超便利店内,销量最佳的物品摆放位置依次为与顾客视线…

ICC2如何写出floorplan信息

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 1)write_def 不用-exclude 的话rows_tracks / vias /blockages / routing_rules信息都会写出去,即便用了-include {macro ports}也不行,所以不介意这些东西的话可以用以下两种种def方式去写f…

RabbitMQ的简单使用 —— Python篇

(一)RabbitMQ的简介 RabbitMq 是实现了高级消息队列协议(AMQP)的开源消息代理中间件。消息队列是一种应用程序对应用程序的通行方式,应用程序通过写消息,将消息传递于队列,由另一应用程序读取 完…

nacos 配置修改.代码实时刷新

再类上用 RefreshScope 更新Value(“${uniqlo.privacy.url:https://wsurl.cc/yourls-api.php}”) private String shortLinkGenerateUrl;的数据可以实时更新 2.再配置类上次用 ConfigurationProperties(prefix “test.privacy”) 和nacos的配置一直 Data Component Configu…

redis高可用-哨兵机制

一:背景 上一节我们已经实现了redis的主从同步,从而实现服务的流量分摊和数据高可用,但是出现故障以后,需要人工手动接入,手动切换主从,来实现故障转移。这是比较麻烦的,毕竟人不能实时盯着服务…

深度学习算法informer(时序预测)(四)(Decoder)

一、DecoderLayer架构如图(不改变输入形状) 二、Decoder整体 包括两部分 1. 多层DecoderLayer 2. 层归一化 代码如下 class DecoderLayer(nn.Module):def __init__(self, self_attention, cross_attention, d_model, d_ffNone,dropout0.1, activati…

java溯本求源之基础(二十五)之--ArrayList常用方法介绍

1. 介绍 1.1简介 ArrayList ArrayList 是 Java 集合框架中的一个类,位于 java.util 包中。它实现了 List 接口,提供了一个动态数组的功能。与普通数组不同,ArrayList 可以在需要时自动调整其容量,以容纳更多的元素。这使得它非常…

《模拟联合国2.9—团队协作》

感谢上海财经大学持续的邀请,今天在阶梯教室举办的《模拟联合国2.0—团队协作》沙盘课程圆满结束。尽管场地的限制带来了一定的挑战,但得益于系统思考中“结构影响行为”的原则,我得以在不同场景中巧妙设计课程结构,极大地促进了大…