利用 Redis 构建全文索引组件

2023-11-03


前言

数据库文章全文搜索中我们很少使用 like 查询,因为假设使用包含查询,我们需要对每个检索词每一篇文章的每个单词进行遍历,检索的时间复杂度则会达到 o(n三次方)。通常,我们会直接使用 elasticsearch 组件来实现全文检索,但我们很少了解全文检索的原理,今天我们尝试使用 redis 来构建一个具有基本检索功能的全文索引组件,将时间复杂度降低到 o(n * log2n)。
这里补充 redislabs 提供的全文检索插件:https://docs.redislabs.com/latest/modules/redisearch/


一、反向索引

在实现这个全文索引组件前,我们需要了解反向索引的数据结构,因为接下来我们将使用反向索引来构建全文检索。
相比正向索引(代表从文档查询到词),而反向索引与之相反则代表从词查询到文档。
下面举个例子:我们使用不同数字代表不同的文档,以下这就是一个正向索引:
0:“hello world”
1:“hello men”
2:“better world”
而反向索引则使用单词作为索引,而文档的数字作为被索引的元素,以下这就是一个反向索引:
“hello” :{0,1}
“world” :{0,2}
“men” :{1}
“better” :{2}
如果要检索"hello men",那么就可以对 {0,1},{1} 取交集,最终得到文档索引 1 。

二、实现代码

注:以下代码使用 Java 实现,但实际上没有用到 Java 语言的特殊实现,主要依靠于 redis 的 SET、ZSET 以及对应的取交集命令 SINTER、SINTERSTORE,如果使用其他语言可做参考
附:Redis的五种数据类型及对应的命令详解

首先使用 spring-boot-starter-data-redis 简化配置,让我们专注于业务。实现代码如下:

package com.ch.demo.redis.search;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.*;
import java.util.stream.Collectors;

@SpringBootApplication
public class Application {

    private static ConfigurableApplicationContext context;
    private static StringRedisTemplate redisTemplate;

    private static Map<String, String> articles = new HashMap<>();

    static {
        // 初始化文章
        articles.put("article_id_1", "there are moments in life when you miss someone so much that you just want to pick them from your dreams and hug them for real");
        articles.put("article_id_2", "when you were born,you were crying and everyone around you was smiling.Live your life so that when you die,you're the one who is smiling and everyone around you is crying");
    }

    public static void main(String[] args) {
        context = SpringApplication.run(Application.class, args);
        redisTemplate = context.getBean(StringRedisTemplate.class);
        // 建立反向索引
        buildIndex();
        System.out.println(search("you were crying"));
        System.out.println(search("you"));
    }

    private static Set<String> search(String txt) {
        // 将搜索语句分词
        List<String> keys = Arrays.asList(txtSplit(txt));
        keys = keys.stream().map(o -> generateKey(o)).collect(Collectors.toList());
        // 对这些分词下的集合取交集
        Set<String> articleIds = redisTemplate.opsForSet().intersect(keys);
        return articleIds;
    }

    /**
     * 构建全文索引
     * <p>这里采用反向索引</p>
     */
    private static void buildIndex() {
        // 将所有文章分词,将每个分词在 redis 上建立 key 为分词值为文章id的集合
        articles.forEach((id, txt) -> {
            String[] keys = txtSplit(txt);
            for (String key : keys) {
                // 如果需要排序则可使用 zset 进行存储
                redisTemplate.opsForSet().add(generateKey(key), id);
            }
        });
    }

    /**
     * 分词器
     *
     * @return String[]
     */
    private static String[] txtSplit(String txt) {
        return txt.split(" ");
    }

    /**
     * redis key 拼接
     *
     * @return String
     */
    private static String generateKey(String key) {
        return "SEARCH:" + key;
    }

}

以上代码运行结果:

[article_id_2]
[article_id_2, article_id_1]

代表 you were crying 查询到文章 article_id_2 ,而 you 则查询到文章 article_id_2、article_id_1。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

利用 Redis 构建全文索引组件 的相关文章

  • 安卓。 onEditorAction 从未被调用

    我正在尝试捕捉从屏幕上移除键盘的事件 并且我正在使用OnEditorActionListener班级 然而 其onEditorAction方法永远不会被调用 这是我的 XML 格式的 EditText
  • 从 PDF 中提取不可选择的内容

    我正在使用 Apache PDFBox 从 PDF 文件中提取页面 但找不到提取不可选择的内容 文本或图像 的方法 从 PDF 文件中选择内容是没有问题的 请注意 相关 PDF 在复制内容方面没有任何限制 至少从我在文件的 文档限制摘要 中
  • 将比较器对象存储在数组中

    我为我的对象定义了 4 个比较器 如下所示 public static Comparator
  • 数组查找时间复杂度和。它是如何存储的

    众所周知 通过索引访问数组的时间复杂度是O 1 Java 的文档ArrayList 它由数组支持 对其也有同样的说法get手术 size isEmpty get set iterator 和 listIterator 操作以恒定时间运行 查
  • Windows 上的虚假唤醒。是否可以?

    我最近学习了 虚假唤醒 有人说这个问题只可能发生在某些类型的 Linux PC 上 我用的是窗户 我为虚假唤醒编写了测试 我得到的结果是这是可能的 但我想向您展示这个测试 也许我在某个地方犯了错误 我的初始变体 import java ut
  • 面试问题 - 在排序数组 X 中搜索索引 i,使得 X[i] = i

    昨天面试时 我被问到了以下问题 考虑一个 Java 或 C 数组X它已排序并且其中没有两个元素是相同的 如何最好地找到索引i这样该索引处的元素也是i 那是X i i 作为澄清 她还给了我一个例子 Array X 3 1 0 3 5 7 in
  • JLabel.setText() 中的换行符

    使用 JLabel setText 时如何插入换行符 我尝试使用 Html 但似乎可以使其适用于 setText 仅适用于 jLabel 的初始声明 最初声明 jlabel 时的方法是 label new JLabel Hello Worl
  • 使用 ScheduledExecutorService 安排每月任务

    我想在该月的某一天的特定时间安排一项任务 每次运行之间的间隔可以设置在 1 到 12 个月之间 在java中 可以使用ScheduledExecutorService以固定的时间间隔调度任务 既然一个月的天数不固定 那么如何实现呢 提前致谢
  • nginx/uwsgi 服务器的持久内存中 Python 对象

    我怀疑这是否可能 但这是问题和提出的解决方案 提出的解决方案的可行性是这个问题的对象 我有一些需要可用于所有请求的 全局数据 我将这些数据保存到 Riak 并使用 Redis 作为缓存层以提高访问速度 目前 数据被分为约 30 个逻辑块 每
  • 将 Spring Boot 应用程序部署到 Heroku 失败并显示“无效标志:--release -> [帮助 1]”

    当我尝试将代码部署到 Heroku 时 通过git push heroku master 我收到 Maven 错误 remote ERROR Failed to execute goal org apache maven plugins m
  • 如何在 Android 中将 EditText 绘制到画布上?

    我想画画 EditText username new EditText context 到我画布上的特定位置 protected void onDraw Canvas canvas 是否可以在基础上画出x y在我的 Java 文件中协调而不
  • java.sql.SQLException: - ORA-01000: 超出最大打开游标数

    我收到 ORA 01000 SQL 异常 所以我有一些与之相关的疑问 最大打开游标是否与 JDBC 连接数完全相关 或者它们也与我们为单个连接创建的语句和结果集对象相关吗 我们正在使用连接池 有没有办法配置数据库中语句 结果集对象的数量 如
  • 在 Java 和 PHP 之间加密/解密字符串

    我使用 AES 加密来加密和解密服务器端的 php 和 Android 应用程序 作为客户端 之间的字符串 PHP 中的加密字符串为 HaxRKnMxT24kCJWUXaVvqDHahzurJQK sYA4lIHql U 在 Java 中是
  • SOAP Web 服务中的用户身份验证

    我提出了一个关于JAX WS 身份验证和授权 如何 https stackoverflow com questions 5314782 jax ws authentication and authorization how to 讨论了安全
  • 在Java中一个接一个地播放WAV文件

    我正在尝试玩几个WAV http en wikipedia org wiki WAV文件一个接一个 我尝试了这个方法 for String file audioFiles new AePlayWave file start 但这会同时播放它
  • Android:如何以编程方式仅圆化位图的顶角?

    我目前正在使用这段代码 Override public Bitmap transform Bitmap source Bitmap result Bitmap createBitmap source getWidth source getH
  • 如何实现再次播放功能?

    我希望在游戏结束时得到提示 如果我还想再玩一次的话 并使用 Y N 输入 退出游戏或重复游戏 我该如何以最有效的方式解决这个问题 编辑 描述资源路径位置类型 类型 Main Main java ScaredyCat src se grupp
  • Spring Boot 健康执行器 - 什么时候上线?

    我找不到任何有关 Springs Health Actuator 何时返回 UP 状态的文档 你能依靠一切吗 Components正在初始化 会不会 Controller准备好满足请求了吗 为了测试应用程序上下文是否已加载 您可以执行此自定
  • Spring Data JPA 和 Exists 查询

    我正在使用 Spring Data JPA 使用 Hibernate 作为我的 JPA 提供程序 并想要定义一个exists附加 HQL 查询的方法 public interface MyEntityRepository extends C
  • SAXParseException:找不到元素“定义”的声明

    我对 camunda 和 DMN 完全陌生 我试图在 spring boot 中运行 DMN 示例 链接在这里 https github com camunda camunda bpm examples tree master dmn en

随机推荐

  • Namomo Test Round 2 C 序列

    题意 给定一个长度为 n n n的序列 a a a 每次可以选择 l
  • Python报错合集(1)

    1 slice None None None 0 is an invalid key X train X test y train y test train test split X resampled y resampled test s
  • MySQL启动过程中的问题

    1 创建my ini 进入MySQL的安装目录 创建配置文件my ini配置文件 写入内容 mysql 设置mysql客户端默认字符集 default character set utf8 mysqld 设置3306端口 port 3306
  • easyExcel设置水印

    1 依赖导入
  • Linux命令入门教程(五):系统管理篇

    Linux系统管理 包括权限管理 网络配置 软件安装 各类参数设置 开关机 系统运行状态等 5 1 权限管理 在linux系统中 用户类别有超级用户和普通用户 只有一个超级用户root 普通用户可以有多个 最根本的区别就是权限不同 在lin
  • iOS17可以更新了!网友实测炫酷值拉满,但续航嘛…

    丰色 发自 凹非寺量子位 公众号 QbitAI iOS 17终于来了 今天凌晨正式推送 有数码博主评价 实用性不高 但酷炫值拉满 旺柴 可以说是一句话概括了 不过有测评发现 更新后续航掉依然的厉害 特别是iPhone XR 可得谨慎了 还登
  • 关于代理抓包,ssl pinning解决方案

    详情见我的博客小生博客 抓包 代理抓包 Fiddler charles能抓http https websocket属于应用层 优点 配置简单 抓取解析ssl方便 缺点 app对代理抓包的检测越发厉害 https http是明文传播 易被修改
  • 轻松搭建基于 SpringBoot + Vue 的 Web 商城应用

    首先介绍下在本文出现的几个比较重要的概念 函数计算 Function Compute 函数计算是一个事件驱动的服务 通过函数计算 用户无需管理服务器等运行情况 只需编写代码并上传 函数计算准备计算资源 并以弹性伸缩的方式运行用户代码 而用户
  • ajax.request,ajaxrequest.js ajaxrequest 0.7最新版 使用AJAXRequest进行AJAX应用程序开发入门小技巧...

    使用AJAXRequest进行AJAX应用程序开发 1 初识AJAXRequest 前言 在发布了AJAXRequest类的几个版本之后 渐渐地有许多朋友用上了它 也有许多朋友问我有没有更详细的说明和示例 不过因为时间的问题以及我能想到的示
  • ClamAV 详解

    1 ClamAV介绍Clam AntiVirus是一个类UNIX系统上使用的反病毒软件包 主要应用于邮件服务器 采用多线程后台操作 可以自动升级病毒库 ClamAV是一个在命令行下查毒软件 因为它不将杀毒作为主要功能 默认只能查出您计算机内
  • 微信小程序canvas生成图片并保存

    需求 做一个类似下图的功能 图片内容是动态的 用canvas画出来 生成临时图片 再保存 实现
  • Python中的isinstance()函数

    1 描述 Python中的 isinstance 函数 是Python中的一个内置函数 用来判断一个函数是否是一个已知的类型 类似 type 2 语法 isinstance object classinfo 参数 object 实例对象 c
  • Servlet工作原理

    文章目录 一 Servlet是什么 二 相关接口 三 Servlet的工作流程 四 Servlet的生命周期 总结 一 Servlet是什么 Servlet 类是 JavaWeb 的三大组件之一 它属于动态资源 是一组 Tomcat 提供给
  • Thread的API介绍

    join 等待当前线程执行完成之后 再执行接下来的语句 如下面的例子所示 在t1线程启动完之后 调用t1 join 的方法 那么会在这里阻塞住 直到t1线程执行完之后 才会继续执行下面的语句 public class RunnableJob
  • 什么是MTTF、MTBF、MTRF?

    1 MTTF 全称是Mean Time ToFailure 即平均失效时间 系统平均能够正常运行多长时间 才发生一次故障 系统的可靠性越高 平均无故障时间越长 2 MTBF 全称是Mean Time BetweenFailure 即平均无故
  • lisp编译器_200行代码实现超轻量级编译器

    前言 本篇内容主要由 https github com jamiebuilds the super tiny compiler 中的注释翻译而来 该项目实现了一款包含编译器核心组成的极简的编译器 希望能够给想要初步了解编译过程的同学提供到一
  • 2021-02-06

    DVWA SQL Injection Blind SQL Injection SQL Injection 即SQL注入 是指攻击者通过注入恶意的SQL命令 破坏SQL查询语句的结构 从而达到执行恶意SQL语句的目的 SQL注入漏洞的危害是巨
  • Qt项目中出现的问题小结

    Qt项目中出现的问题小结 写在前面 总结这个星期自学Qt踩过的一些坑 并不包含所有问题 仅仅是基于自己所做的小界面而言 文章目录 Qt项目中出现的问题小结 1 Qt中文乱码 2 关于Qt调用vs编译的dll控件 3 关于动态链接库导出类与函
  • xss靶场挑战之旅总结

    第一关 没有做任何的过滤 我们试下 第二关 我们用 gt 有转义 参考HTML的转义 输入的 gt lt 被做了转义处理 变成了 gt lt 我们用javascript里边的oninput事件试试 我们用12 ninput alert 12
  • 利用 Redis 构建全文索引组件

    文章目录 前言 一 反向索引 二 实现代码 前言 数据库文章全文搜索中我们很少使用 like 查询 因为假设使用包含查询 我们需要对每个检索词每一篇文章的每个单词进行遍历 检索的时间复杂度则会达到 o n三次方 通常 我们会直接使用 ela