leveldb前缀匹配查找Seek
个人随笔 (Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)
参考:https://github.com/google/leveldb/blob/main/include/leveldb/db.h
参考:百度AI
1. 背景
最近偶然发现了,leveldb前缀匹配查找的功能。
之前没有从这个角度去想过Seek方法,尝试使用之后,效率还是很好的。
另外今天使用关键词查找时,百度AI也给了一个很棒的例子。
时不我待,下面也谈一谈该技术点,以及这个技术点的背后支持,leveldb为此做的实现。
2. 前缀匹配需求
先说前缀查找的需求:
我们已知的是leveldb是一个KV数据库,KV数据提供的形如一个排序队列,按照key排序的队列;
当我们在leveldb库中存了许多的key与value值之后,某些时候,我们希望找出某个prefix开头的元素列表。
例如,我们存储了 公司名称key 到 公司简介value的 信息,我们希望查询公司名称 以"中国"开头的公司信息;
按照KV数据库的排序特点,在Key的排序队列中,缺省是字节比较,前缀相同的是存储到一块的,会和前缀不同的分开;
如果我们能查询到第一条前缀为"中国"的公司的key-value键值数据,往后继续查找,就能找到其它的数据了。
3. 技术实现
按照上述推断,如果我们用leveldb::Get()方法的话,是不可以的,
一方面是:当我们使用前缀查找时,是不知到排序第一条的公司名称;
另一方面是:Get方法直接提供的value数据,无法来找到下一条数据。
// If the database contains an entry for "key" store the// corresponding value in *value and return OK.//// If there is no entry for "key" leave *value unchanged and return// a status for which Status::IsNotFound() returns true.//// May return some other Status on an error.virtual Status Get(const ReadOptions& options, const Slice& key,std::string* value) = 0;
对于数据查找接口,就只剩余iterator接口了,iterator接口可以用于遍历leveldb的数据。
常用的方法是,先NewIterator,然后使用iter.SeekToFirst,之后使用Next遍历数据。
对于Iterator::Seed(const Slice& target)方法,在leveldb的内部Get方法中是有被使用到的。
同样的,这个Seek方法我们也可以直接调用使用,这个方法就是我们做前缀匹配的关键支持接口。
// Return a heap-allocated iterator over the contents of the database.// The result of NewIterator() is initially invalid (caller must// call one of the Seek methods on the iterator before using it).//// Caller should delete the iterator when it is no longer needed.// The returned iterator should be deleted before this db is deleted.virtual Iterator* NewIterator(const ReadOptions& options) = 0;class LEVELDB_EXPORT Iterator {public:Iterator();Iterator(const Iterator&) = delete;Iterator& operator=(const Iterator&) = delete;virtual ~Iterator();// An iterator is either positioned at a key/value pair, or// not valid. This method returns true iff the iterator is valid.virtual bool Valid() const = 0;// Position at the first key in the source. The iterator is Valid()// after this call iff the source is not empty.virtual void SeekToFirst() = 0;// Position at the last key in the source. The iterator is// Valid() after this call iff the source is not empty.virtual void SeekToLast() = 0;// Position at the first key in the source that is at or past target.// The iterator is Valid() after this call iff the source contains// an entry that comes at or past target.virtual void Seek(const Slice& target) = 0;// Moves to the next entry in the source. After this call, Valid() is// true iff the iterator was not positioned at the last entry in the source.// REQUIRES: Valid()virtual void Next() = 0;// Moves to the previous entry in the source. After this call, Valid() is// true iff the iterator was not positioned at the first entry in source.// REQUIRES: Valid()virtual void Prev() = 0;...
}
4. 技术理解
一般而言,对于经常使用std库的我们,可能会觉得Seek接口就和std库的find等接口类似,找一个元素,找到了返回元素,找不到了,返回指向末尾flag元素。
这点是一个思维误区了,我之前也有这个思维误区,我也缺省认为Seek就是查找元素用的,实际这样理解的不准确。
Seek所代表的是,在这个KV的排序队列上,找到一个>=TargetKey的元素后,然后停下来,Seek更多表达的是找到一个符合条件,停止下来的元素点。
所以Seek操作之后呢,并不是说iter.Valid()就查找到元素了,而是说iter.Valid()表达找到符合>=Tagetkey的这个点了。
如果要判定是否找到了,是==Tagetkey,需要Seek之后,再来判断一下。
// Position at the first key in the source that is at or past target.// The iterator is Valid() after this call iff the source contains// an entry that comes at or past target.virtual void Seek(const Slice& target) = 0;
Seek的这种实现方式—[找到一个>=TargetKey的元素后,然后停下来],就为我们做前缀匹配提供了功能支持。
前缀匹配,也就是找到符合前缀的第一个元素,方便我们沿着这个元素,继续找到剩余符合该前缀的所有元素。
在leveldb的内部存储里面,MemTable层(Mem与Imm),提供了Iterato封装方法,各个level的SST持久化文件,也都封装提供了Iterator方法,通过这些内存存储的包装,提供了总体的leveldb数据遍历查找Iterator方法。通过Seek方法,让Iterator指向第一个符合>=Targetkey的元素,来最终让Iterator指向这个排序key-value对列的首个符合条件的元素,之后附加后续的prefix比对,就可以支持前缀查找。
5. 附:样例代码
下面附一段,由百度AI生成的leveldb前缀匹配样例代码,这段代码生动演示了前缀匹配实现。
这段代码
首先,打开了一个LevelDB数据库,然后写入了一些带有不同前缀的键值对。
接着,它使用了一个迭代器来进行前缀匹配查询,并打印出所有匹配的键值对。
最后,代码关闭了数据库并释放了相关资源。
#include <iostream>
#include <string>
#include "leveldb/db.h"int main() {leveldb::DB* db;leveldb::Options options;options.create_if_missing = true;leveldb::Status status = leveldb::DB::Open(options, "./testdb", &db);if (!status.ok()) {std::cerr << "Error opening db: " << status.ToString() << std::endl;return -1;}// 写入一些数据status = db->Put(leveldb::WriteOptions(), "apple", "1");if (status.ok()) status = db->Put(leveldb::WriteOptions(), "applet", "2");if (status.ok()) status = db->Put(leveldb::WriteOptions(), "banana", "3");if (!status.ok()) {std::cerr << "Error writing to db: " << status.ToString() << std::endl;return -1;}// 进行前缀匹配查询std::string prefix = "app";leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());for (it->Seek(prefix);it->Valid() && it->key().starts_with(prefix);it->Next()) {std::cout << it->key().ToString() << ": " << it->value().ToString() << std::endl;}delete it;// 关闭数据库delete db;return 0;
}
个人随笔 (Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)
相关文章:

leveldb前缀匹配查找Seek
个人随笔 (Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu) 参考:https://github.com/google/leveldb/blob/main/include/leveldb/db.h 参考:百度AI 1. 背景 最近偶然发现了,leveldb前缀匹配查找的功能。 之前没有从这个角度去想过See…...

【自动驾驶】ros如何隔绝局域网内其他电脑播包
1.问题 可能碰到自己播包的时候,别人播包的传到我们电脑上,导致无法分析问题,或者出现一些奇怪的现象。 2.解决 export ROS_LOCALHOST_ONLY1 在终端加上这句话,或者在~/.bashrc中添加,通过source ~/.bashrc使其生…...

MySQL程序
目录 MySQL程序 常用的MySQL的程序 mysqld程序 mysql客户端 客户端命令的常用的选项 配置文件 配置文件语法 MySQL客户端命令 编辑 .sql 文件中执行SQL语句 mysqlcheck (表维护程序) Mysqldump(数据库备份程序) mysql…...

吉林省自闭症寄宿学校:提供个性化培养方案
在吉林省的怀抱中,隐藏着一片温馨而特殊的天地——星贝育园自闭症儿童寄宿制学校。这里,不是简单的教育场所,而是无数自闭症儿童梦想启航的港湾,是他们感受爱、学习成长、绽放自我光芒的温馨家园。 自闭症,一个逐渐被…...

Java基础 — Java 虚拟机(上篇)
该文章属于Java进阶部分的JVM入门,本章讲述了JVM的历史、Java源代码到机器码的过程以及 Class字节码文件的内部结构等。 了解了这篇文章,能让你深入地了解JVM知识,保证在短时间内掌握JVM! JVM 入门教程(上篇࿰…...

C++ | Leetcode C++题解之第435题无重叠区间
题目: 题解: class Solution { public:int eraseOverlapIntervals(vector<vector<int>>& intervals) {if (intervals.empty()) {return 0;}sort(intervals.begin(), intervals.end(), [](const auto& u, const auto& v) {retur…...

AI编辑器CURSOR_CURSOR安装教程_使用AI进行编码的最佳方式。
一、CUROR简介 作为一个在代码海洋里遨游多年的老程序员,我得说,遇到CURSOR这位AI编辑器,就像是编程路上偶遇了一位智慧而又贴心的老友。 想象一下,夜深人静,你正埋头于那些错综复杂的逻辑和无尽的bug之中࿰…...

华为HarmonyOS灵活高效的消息推送服务(Push Kit) -- 10 推送实况窗消息
场景介绍 实况窗是一种帮助用户聚焦正在进行的任务,方便快速查看和即时处理的通知形态。有关实况窗简介、权限申请、开放场景、设计规范等说明,请参见Live View Kit简介。 通过Push Kit发送的实况窗消息支持三种操作类型,分别是: 实况窗消息操作类型 支持操作的场景类型 …...

探索 Go 语言程序实体:揭开神秘面纱
《探索 Go 语言程序实体:揭开神秘面纱》 在 Go 语言的世界里,程序实体是构建强大应用的基石。它们就像是魔法世界中的元素,各自有着独特的能力和用途。让我们一起深入探索 Go 语言程序实体的那些事儿。 一、什么是 Go 语言程序实体? 在 Go 语言中,程序实体是指可以被命…...

深入理解端口、端口号及FTP的基本工作原理
FTP是TCP/IP的一种具体应用,FTP工作在OSI模型的第七层,TCP模型的第四层上,即应用层,FTP使用的是传输层的TCP传输而不是UDP,这样FTP客户在和服务器建立连接前就要经过一个被广为熟知的“三次握手”的过程,其…...

9.3 Linux_文件I/O_相关函数
打开与关闭 1、打开文件 int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);返回值:成功返回文件描述符,失败返回EOF pathname:文件路径 flags:标志,其中O_RDO…...

点亮一个LED灯
一、任务分析 一个灯怎么样才会亮? 图中的小灯两端接正负极,小灯就会点亮,但是我们不能主动控制灯的亮灭,于是加入了开关。开关打开断开小灯正极,小灯就会熄灭,反之则点亮。 在板子上的灯是如何连接的&…...

分布式框架 - ZooKeeper
一、什么是微服务架构 1、单体架构 顾名思义一个软件系统只部署在一台服务器上。 在高并发场景中,比如电商项目,单台服务器往往难以支撑短时间内的大量请求,聪明的架构师想出了一个办法提高并发量:一台服务器不够就加一台&am…...

8月份,AI图像生成领域web端产品排行榜及产品是做什么的
看全球用户量级别的Top12(WEB)。 排名 产品名 分类 8月访问量 上月对比 1 Canva AI Design Tool 711.9M 6.48% 2 Remove.bg AI Image Editor 72.79M 2.84% 3 Fotor AI Image Editor 15.62M 2.34% 4 Civitai Model Training & …...

Sqlite_Datetime列选择三月的行
In SQLite, use the strftime function to extract components from a date/time value SELECT * FROM table WHERE strftime(%m, datemonth) 03;strftime(‘%m’, datemonth): extracts the month part from the datemonth column as a string (with leading zeros for sing…...

spring里面内置的非常实用的工具
一 、请求数据记录 Spring Boot提供了一个内置的日志记录解决方案,通过 AbstractRequestLoggingFilter 可以记录请求的详细信息。 AbstractRequestLoggingFilter 有两个不同的实现类,我们常用的是 CommonsRequestLoggingFilter。 通过 CommonsRequestL…...

计算机毕业设计 基于Python内蒙古旅游景点数据分析系统 Django+Vue 前后端分离 附源码 讲解 文档
🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点…...

centos7 docker部署nacos
1. 一行代码安装git yum -y install git 2. 下载最新版nacos源码: git clone https://github.com/nacos-group/nacos-docker.git 进入nacos-docker文件 cd nacos-docker 3.docker安装数据库Mysql8 按这个来就行,非常好 Docker安装mysql8-超详细、每…...

短视频矩阵源码/短视频矩阵系统搭建/源码开发知识分享
集星云推智剪获客系统,通过自主研发的高效发布模式,为企业提供稳定的接口与自动化操作,助力企业实现短视频矩阵的构建。该系统整合了十大核心功能,包括AI辅助文案撰写、视频剪辑、智能去重、内容拆分、文字转语音、文本提取、批量…...

Git使用教程-将idea本地文件配置到gitte上的保姆级别教程
🤹♀️潜意识起点:个人主页 🎙座右铭:得之坦然,失之淡然。 💎擅长领域:前端 是的,我需要您的: 🧡点赞❤️关注💙收藏💛 是我持…...

论文 | Reframing Instructional Prompts to GPTk’s Language
作者:Swaroop Mishra, Daniel Khashabi, Chitta Baral, Yejin Choi, Hannaneh Hajishirzi 论文摘要:语言模型 (LM) 更容易遵循哪些类型的指令提示? 我们通过进行广泛的实证分析来研究这个问题,这些分析阐明了成功指令提示的重要特…...

C++ Qt / VS2019 +opencv + onnxruntime 部署语义分割模型【经验2】
前序工作 C Qt / VS2019 opencv onnxruntime 部署语义分割模型【经验】 引言 前序工作中介绍了Pytorch模型如何转为ONNX格式,以及在Python中如何使用onnx模型 介绍了如何在VA或QT中配置Onnxruntime运行库 本文重点列出全部源代码及其使用 依赖库 onnxruntime…...

代码随想录算法训练营Day9
232.用栈实现队列 Collection——List——Vector类——Stack类 class MyQueue {Stack<Integer> stackIn;Stack<Integer> stackOut;public MyQueue() {stackInnew Stack();stackOutnew Stack();} public void push(int x) {stackIn.push(x);}public int pop() {no…...

2025秋招NLP算法面试真题(二十)-有监督微调基本概念
1.基本概念 1.微调方法是啥?如何微调? 微调(Fine-tuning)是一种迁移学习的方法,用于在一个预训练模型的基础上,通过在特定任务的数据上进行有监督训练,来适应该任务的要求并提高模型性能。微调利用了预训练模型在大规模通用数据上学习到的语言知识和表示能力,将其迁移…...

使用宝塔部署项目在win上
项目部署 注意: 前后端部署项目,需要两个域名(二级域名,就是主域名结尾的域名,需要在主域名下添加就可以了),前端一个,后端一个 思路:访问域名就会浏览器会加载前端的代…...

[大语言模型-论文精读] Diffusion Model技术-通过时间和空间组合扩散模型生成复杂的3D人物动作
Generation of Complex 3D Human Motion by Temporal and Spatial Composition of Diffusion Models L Mandelli, S Berretti - arXiv preprint arXiv:2409.11920, 2024 通过时间和空间组合扩散模型生成复杂的3D人物动作 摘要 本文提出了一种新的方法࿰…...

vue 引入 esri-loader 并加载地图
记录一下: npm i esri-loader 引入css 在app.vue中 <style> import url(https://js.arcgis.com/4.6/esri/css/main.css); </style> 新建js文件 在js文件中引入esri-loader 并加载其init.js文件 加载init.js 需要其中的loadScript 部分如下&…...

LobeChat:使用服务端数据库部署 - Docker+NextAuth(github)+腾讯云
总流程 Docker部署 身份验证服务-NextAuth github S3存储服务 腾讯云COS 1. 安装Docker brew install docker --cask2. 创建pgvector容器(PostgresSQL) docker run --name [myPgvector] -p 5432:5432 -e POSTGRES_PASSWORD[pwd] -d -e POSTGRES_USER[username] pgvector/…...

长列表加载性能优化
一、长列表优化概述 列表是应用开发中最常见的一类开发场景,它可以将杂乱的信息整理成有规律、易于理解和操作的形式,便于用户查找和获取所需要的信息。应用程序中常见的列表场景有新闻列表、购物车列表、各类排行榜等。随着信息数据的累积,特…...

Vue ElemetUI table的行实现按住上下键高亮上下移动效果
1、添加初始化的方法 // 添加键盘事件监听器: mounted() {window.addEventListener(keydown, this.handleKeydown);}, // 这段代码的作用是在 Vue 组件销毁之前移除一个键盘事件监听器 // 这样做可以确保当组件不再使用时,不会留下任何未清理的事件监听…...