Elasticsearch 中的高效按位匹配

news2024/10/23 10:08:09

作者:来自 Elastic Alexander Marquardt

探索在 Elasticsearch 中编码和匹配二进制数据的六种方法,包括术语编码(我喜欢的方法)、布尔编码、稀疏位位置编码、具有精确匹配的整数编码、具有脚本按位匹配的整数编码以及使用 ESQL 进行按位匹配的整数编码,并提供实际示例和用例。

简介

二进制编码是现代应用中的一项重要技术,尤其是在物联网设备监控等领域,这些领域需要持续处理大量二进制传感器数据或操作标志。高效管理和搜索此类数据对于实时分析和决策至关重要。为了实现这一点,按位匹配是一种基于二进制值进行过滤的强大工具,可以实现精确的数据提取。通过正确的数据建模,Elasticsearch 不仅支持按位匹配,而且性能极佳。

在撰写本文时,Elasticsearch 没有用于按位匹配的原生运算符,而 Lucene 也不直接支持按位匹配。为了克服这一限制,本文介绍了 Elasticsearch 中的六种二进制编码和按位匹配方法:术语编码(我首选的方法)、布尔编码、稀疏位位置编码、带精确匹配的整数编码、带脚本按位匹配的整数编码以及带 ESQL 的按位匹配整数编码。

术语编码 - terms encoding

使用术语进行二进制表示可利用 Elasticsearch 优化的基于术语的查询。此方法涉及将每个位表示为存储在关键字字段中的术语。

术语编码的优点

基于术语的方法允许 Elasticsearch 使用优化的数据结构,从而即使对于大型数据集也能实现高效查询。此外,此方法在需要频繁查询不同位组合的情况下具有很好的扩展性,因为每个位都被视为可以索引和搜索的独立实体。

术语编码的缺点

此方法要求在将数据存储在 Elasticsearch 中之前对数据进行预处理以将其转换为术语编码格式。此外,按位查询必须构建为一系列术语匹配,如下所示。此外,由于每个二进制序列由多个术语表示,因此这可能会占用比整数表示所需的更多存储空间。

设置术语编码的环境

定义关键字表示的映射:

PUT test_terms_encoding
{
 "mappings": {
   "properties": {
     "terms_encoded_bits": {
       "type": "keyword"
     }
   }
 }
}

使用术语编码对文档进行索引

使用二进制位表示对文档进行索引:

POST test_terms_encoding/_doc/1
{
 "terms_encoded_bits": ["b3=0", "b2=1", "b1=1", "b0=0"] // binary 0110
}
POST test_terms_encoding/_doc/2
{
 "terms_encoded_bits": ["b3=1", "b2=0", "b1=1", "b0=0"] // binary 1010
}

使用术语编码进行查询

查询 b3 为真、b0 为假的文档(即上面的 _id=2 的文档)

GET test_terms_encoding/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "terms_encoded_bits": "b3=1"
          }
        },
        {
          "term": {
            "terms_encoded_bits": "b0=0"
          }
        }
      ]
    }
  }
}

布尔编码

此方法对每个位使用单独的布尔字段,提供对特定位的清晰直接访问。

布尔编码的优点

布尔编码方法具有 “术语编码” 方法的所有优点,有些人可能发现这种方法更直观。对于某些数据集,它可能需要的存储空间也略少,因为每个字段只存储一个布尔值,而不是字符串。

布尔编码的缺点

这具有 “术语编码” 方法列出的所有缺点。这种方法的另一个缺点是,由于我们为每个位创建了一个新字段,这会导致映射爆炸。

设置布尔编码的环境

使用布尔字段定义映射:

PUT test_boolean_encoding
{
  "mappings": {
    "properties": {
      "b3": { "type": "boolean" },
      "b2": { "type": "boolean" },
      "b1": { "type": "boolean" },
      "b0": { "type": "boolean" }
    }
  }
}

使用布尔编码对文档进行索引

使用每个位的布尔值对文档进行索引:

POST test_boolean_encoding/_doc/1
{
 "b3": false, 
 "b2": true,
 "b1": true,
 "b0": false
} // binary 0110 – integer 6
POST test_boolean_encoding/_doc/2
{
 "b3": true,
 "b2": false,
 "b1": true,
 "b0": false
} // binary 1010 – integer 10

使用布尔编码进行查询

要查询 b3 为真、b0 为假的文档(即上面的 _id=2 的文档):

GET test_boolean_encoding/_search
{
 "query": {
   "bool": {
     "filter": [
       {
         "term": {
           "b3": true
         }
       },
       {
         "term": {
           "b0": false
         }
       }
     ]
   }
 }
}

稀疏位位置编码 - Sparse Bit Position Encoding

此方法仅对数组中设置为 true 的位的位置进行编码。

稀疏位位置编码的优点

如果绝大多数文档通常没有任何位设置为 true,那么与以前的方法相比,这种方法在存储方面可能更有效。例如,你可以想象,表示警告标志的位很少为 true 的数据集,这将导致位位置编码数组为空(因此节省空间),而这些数组对于很大一部分文档而言都是空的。

稀疏位位置编码的缺点

此方法的一个缺点是,查询不为 true 的位需要使用 must_not 运算符。但是,使用 must_not 进行查询可能会导致性能开销,因为 Elasticsearch 需要扫描文档以验证某些值的缺失,这比直接查询特定术语的存在效率更低。在大型数据集中,这可能会减慢处理速度。另一个缺点是,如果数据始终有许多位设置为 true,那么这将需要一长串整数来表示,这会增加存储要求。最后,与其他方法一样,此方法需要预处理数据,将其转换为稀疏位位置编码,然后再将其存储在 Elasticsearch 中。

设置稀疏位位置编码的环境

定义整数数组的映射:

PUT test_sparse_encoding
{
  "mappings": {
    "properties": {
      "sparse_bit_positions": {
        "type": "integer"
      }
    }
  }
}

使用稀疏位位置编码对文档进行索引

使用位位置编码为整数对文档进行索引:

POST test_sparse_encoding/_doc/1
{
  "sparse_bit_positions": [2, 1] // binary 0110
}
POST test_sparse_encoding/_doc/2
{
  "sparse_bit_positions": [3, 1] // binary 1010
}

使用稀疏位位置编码进行查询

要查询 b3 为真、b0 为假的文档(即上面的 _id=2 的文档):

GET test_sparse_encoding/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "sparse_bit_positions": 3
          }
        }
      ],
      "must_not": [
        {
          "term": {
            "sparse_bit_positions": 0
          }
        }
      ]
    }
  }
}

带精确匹配的整数编码

在这种方法中,二进制值被编码为整数。这是一种直观的方法,特别是当你需要高效地存储和查询完整的二进制序列(即整数)时。

带精确匹配的整数编码的优点

在迄今为止讨论的方法中,这种方法最有可能直接映射到源系统中数据存储的方式,源系统通常将二进制序列表示为整数。因此,使用这种方法存储文档可能比其他方法需要更少的预处理。

带精确匹配的整数编码的缺点

这种方法仅讨论表示二进制序列的整数值的精确匹配。它不解决整数内的按位匹配问题。它还要求你在将二进制值存储在 Elasticsearch 中之前将其转换为整数。

设置整数编码的环境

定义整数编码的映射:

PUT test_integer_encoding
{
 "mappings": {
   "properties": {
     "integer_representation": {
       "type": "integer"
     }
   }
 }
}

使用整数编码对文档进行索引

通过将二进制序列转换为整数来对文档进行索引:

POST test_integer_encoding/_doc/1
{
 "integer_representation": 6  // binary 0110
}
POST test_integer_encoding/_doc/2
{
 "integer_representation": 10 // binary 1010
}

使用整数编码进行查询

以下查询检索二进制表示等于特定值的文档 - 在此示例中,文档包含整数表示 0110 且 _id=1:

GET test_integer_encoding/_search
{
 "query": {
   "term": {
     "integer_representation": 6 // binary 0110
   }
 }
}

使用脚本按位匹配进行整数编码

在这种方法中,我们扩展了将二进制值编码为整数的概念,并利用 scripted query 功能来查询整数值中设置的各个位。本文将对这种方法进行讨论,以保证完整性,但请记住,大量使用脚本查询将给集群带来额外的工作负载,并且可能比其他方法更慢、效率更低。

使用脚本按位匹配进行整数编码的优点

这种方法具有“使用精确匹配进行整数编码”方法的优点。另一个优点是可以匹配各个位。

使用脚本按位匹配进行整数编码的缺点

这种按位匹配方法没有利用 Elasticsearch 构建的数据结构来确保快速高效的查询。因此,这种方法可能会导致查询速度变慢,并且比前面提到的方法需要更多的资源。因此,我通常会推荐前面讨论的方法。

设置和索引文档

在本节中,我们将使用在第二个名为 “精确匹配的整数编码” 的章节中填充的相同索引。

查询

要查询 b3 为真且 b0 为假的文档(即上面的 _id=2 的文档),我们可以使用脚本查询。以下查询满足这些要求,并附有注释以解释逻辑:

GET test_integer_encoding/_search
{
  "query": {
    "bool": {
      "filter": {
        "script": {
          "script": {
            "source": """
            // b3 is true 
            // i.e. "integer_representation" AND 1000 == 1000
            // Keep in mind that 1000 binary == 8 in integer
            ((doc['integer_representation'].value & 8) == 8) && 
            
            // b0 false 
            // i.e. "integer_representation" AND 0001 == 0
            ((doc['integer_representation'].value & 1) == 0)"""   
          }
        }
      }
    }
  }
}

使用 ES|QL 进行整数编码以进行按位匹配

与 “使用脚本按位匹配进行整数编码” 方法一样,此方法也可以匹配单个位,但它利用的是 ES|QL 而不是脚本查询。本文将对此方法进行讨论,以保证完整性,但大量使用此方法可能会在集群上产生额外的工作负载,并且可能比其他方法更慢、效率更低。

使用 ES|QL 进行整数编码以进行按位匹配的优势

此方法具有与 “使用脚本按位匹配进行整数编码” 相同的优势。另一个优势是它利用了在设计时考虑了性能的 ES|QL。

使用 ES|QL 进行整数编码以进行按位匹配的缺点

尽管此方法利用了 ES|QL,但它无法直接使用预构建的数据结构进行按位匹配。因此,此方法可能会导致查询速度变慢,并且比许多其他方法需要更多的资源。

设置和索引文档

在本节中,我们将使用在第二个名为“精确匹配的整数编码”的章节中填充的相同索引。

查询

要查询 b3 为真且 b0 为假的文档(即上面的 _id=2 的文档),我们可以使用 ES|QL。以下查询满足这些要求,并附有注释以解释逻辑:

POST /_query?format=txt
{
  "query": """
  FROM test_integer_encoding METADATA _index, _id
  // The following uses division to shift the bit we are interested 
  // in, to the right. ie. dividing by 8 (or b1000 - corresponding to b3) 
  // shifts b3 to the least significant bit position, or b0. 
  // Additionally, the rightmost bits are dropped.
  // Then the modulus by 2 checks if the new (post shift) 
  // value of b0 (formerly b3)is odd or even (1 or 0)
  | WHERE (integer_representation / 8 % 2 == 1)  // b3 is true
  | WHERE (integer_representation / 1 % 2 == 0)  // b0 is false
  | KEEP _id, integer_representation
  """
}

结论

在本文中,我们探讨了六种按位匹配方法 —— 术语编码(我首选的方法)、布尔编码、稀疏位位置编码、精确匹配的整数编码、脚本按位匹配的整数编码以及使用 ES|QL 进行按位匹配的整数编码。这展示了如何应用不同的方法来有效地处理 Elasticsearch 中的按位匹配。每种方法都有其优点和权衡,具体取决于应用程序的特定要求。

对于需要单独位匹配的场景,基于术语和布尔字段的方法效果很好,应该是有效的。在整数数组中表示真实位位置为稀疏位序列提供了一种紧凑而灵活的解决方案。将二进制序列编码为整数可能适合整个序列操作,但代价是失去有效查询单个位的能力。我们还可以使用脚本查询或 ES|QL 查询整数中的单个位,但这些方法可能不如其他方法有效。

致谢

感谢 Honza Kral 提出使用术语和整数对单个位进行编码的想法,感谢 Alexis Charveriat 建议使用 ES|QL 进行按位匹配的方法,感谢 Carly Richmod 在技术审查过程中提出的宝贵建议。

准备好自己尝试一下了吗?开始免费试用。

想要获得 Elastic 认证?了解下一期 Elasticsearch 工程师培训何时开始!

原文:Efficient bitwise matching in Elasticsearch - Search Labs

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

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

相关文章

基于vue框架的的二手车交易系统的设计与实现thx7v(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能:用户,卖家,车辆类型,二手车,在线留言,订单信息 开题报告内容 基于Vue框架的二手车交易系统的设计与实现开题报告 一、课题背景及意义 随着汽车消费市场的日益成熟与消费者换车频率的增加,二手车交易市场逐渐成为汽车市场的…

pycharm配置git版本控制

今天记录一下如何在pycharm工具中配置git版本控制,主要分以下步骤: 1、安装git 首先需要有git环境,去git官网下载git安装包,下一步下一步执行安装完成即可 2、在pycharm中配置git路径 下载git后,在pycharm的 setti…

「AIGC」n8n AI Agent开源的工作流自动化工具

n8n AI Agent 是一个利用大型语言模型(LLMs)来设计和构建智能体(agents)的工具,这些智能体能够执行一系列复杂的任务,如理解指令、模仿类人推理,以及从用户命令中理解隐含意图。n8n AI Agent 的核心在于构建一系列提示(prompts),使 LLM 能够模拟自主行为。 传送门→ …

GAMES104:17 游戏引擎的玩法系统:高级AI-学习笔记

文章目录 课前QA一,层次任务网络(Hierarchical Tasks Network,HTN)1.1 HTN Framework1.2 HTN Task Types1.2.1 Primitive Task基本任务1.2.2 Compound Task符合任务 1.3 Planning1.4 Replan1.5 总结 二,目标导向行为规…

在ECS实例上搭建WordPress博客平台

WordPress是使用PHP语言开发的博客平台,在支持PHP和MySQL数据库的服务器上,您可以用WordPress搭建自己的网站,也可以用作内容管理系统(CMS)。本教程介绍如何在不同操作系统的ECS实例上,手动搭建WordPress网…

SonarQube快速实践

SonarQube快速实践 1. 简介 SonarQube 是一个本地部署的代码分析工具,旨在检测30多种编程语言、框架和基础设施即代码(IaC)平台中的代码问题。通过直接集成到您的持续集成(CI)流水线中或在我们支持的DevOps平台之一上…

转行AI产品经理,第二步怎么走

之前写了一篇文章《转行AI产品经理,第一步怎么走》,好多小伙伴私信我,和我聊了一些细节,我感觉有必要再聊一聊,转行AI产品经理,第二步怎么走。 在上一篇文章里我们聊了一个小糖人游戏,从而得出…

用AI怎样来迭代优秀的学习法,AI+费曼学习法的妙用!

大家好,我是Shelly,一个专注于输出AI工具和科技前沿内容的AI应用教练,体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具,拥抱AI时代的到来。 AI工具集1:大厂AI工具【共23款…

Quartus Ⅱ仿真 2.三人表决电路

奥里给,一起加油啊,我会陪着你们的! 仿真波形: 输出结果: 介绍: 三人表决电路是一种数字逻辑电路,用于实现三个输入信号的多数表决。在这种电路中,如果至少有两个输入为高电平&a…

MySQL-事物隔离级别

1. MySQL事物的四种隔离级别 1.1 读未提交(READ UNCOMMITTED) READ UNCOMMITED提供了事物之间最小限度的隔离,除了幻读和不可重复读取的操作外,处于这个隔离级别的事务可以读到其它事务还未提交的数据。 1.2 读已提交&#xf…

利用 Direct3D 绘制几何体—7.编译着色器

在 Direct3D 中,着色器程序必须先被编译为一种可移植的字节码。接下来,图形驱动程序将获取这些字节码,并将其重新编译为针对当前系统 GPU 所优化的本地指令 [ATI1]。我们可以在运行期间用下列函数对着色器进行编译。 HRESULT D3DCompileFrom…

创建型模式-----(单例模式)

目录 基本概念 饿汉式: 懒汉式: 上锁双判空版本 std::call_once版本: C11标准后局部静态变量版本: 项目中单例模板的应用 基本概念 单例模式:在程序运行期间只有一份,与程序生存周期一样,…

对比学习论文随笔 1:正负样本对(Contrastive Learning 基础论文篇)

为了阅读的流畅,当前针对相同的代理任务按时间顺序进行梳理,涉及仅使用正负样本思想且优化目标一致的「基础」论文(2018-2020),编码器均采用 ResNet。 文章目录 前言对比学习和代理任务(Pretext task&#…

浪潮云启操作系统(InLinux)bcache缓存实践:理解OpenStack环境下虚拟机卷、Ceph OSD、bcache设备之间的映射关系

前言 在OpenStack平台上,采用bcache加速ceph分布式存储的方案被广泛用于企业和云环境。一方面,Ceph作为分布式存储系统,与虚拟机存储卷紧密结合,可以提供高可用和高性能的存储服务。另一方面,bcache作为混合存储方案&…

Java笔试06

在Java中,异常可以分为两大类:编译时异常(编译时检查异常)和运行时异常(非编译时检查异常)。 编译时异常(Checked Exceptions)是指在编译时期必须被捕获或声明抛出的异常。这些异常…

字节流写入文件

一、创建输出流对象表示的文件三种方式 方法一: FileOutputStream fos new FileOutputStream("fos.txt",true);//最简便方法二: FileOutputStream fos new FileOutputStream(new File("fos.txt"));方法三; File f ne…

Python | Leetcode Python题解之第502题IPO

题目: 题解: class Solution:def findMaximizedCapital(self, k: int, w: int, profits: List[int], capital: List[int]) -> int:if w > max(capital):return w sum(nlargest(k, profits))n len(profits)curr 0arr [(capital[i], profits[i]…

HTML作业

作业 复现下面的图片 复现结果 代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><body><form action"#"method"get"enctype"text/plain"><…

Java程序设计:spring boot(7)——数据访问操作

目录 1 查询操作 1.1 接口方法定义 1.2 映射文件配置 1.3 UserService 1.4 UserController 2 添加操作 2.1 接口方式定义 2.2 映射文件配置 2.3 添加 commons-lang3 依赖 2.4 AssertUtil ⼯具类 2.5 ParamsException ⾃定义异常 2.6 UserService 2.7 ResultInfo …

UDP传输协议Linux C语言实战

文章目录 1.UDP简介1.1特点1.2 UDP协议头部格式1.2.1 **UDP头部**&#xff1a;1.2.2 **头部意义**&#xff1a;1.2.3 **头部参数**&#xff1a; 1.3 UDP数据长度控制1.4 UDP协议建立框架 2. 函数介绍2.1 sendto函数2.2 recvform函数2.3 其他函数 3.实例3.1 通用结构体、IPV4结构…