Elasticsearch 中的高效按位匹配

作者:来自 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

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

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

相关文章

Maven 不同环境灵活构建

需求: 使用 Maven根据不同的构建环境(如开发、测试、生产)来定义不同的配置,实现灵活的构建管理。 需要Demo项目的可以参考:我的demo项目 一、项目分层 一般的初创项目不会有特别多的配置文件,所以使用 spring.profile…

【333基于Java Web的考编论坛网站的设计与实现

毕 业 设 计(论 文) 考编论坛网站设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多,其次数据出错率比较高,而且对错误的数据进行更改也比较困难,最后,检索数据费事费力。因此,在计…

linux下gpio模拟spi三线时序

目录 前言一、配置内容二、驱动代码实现三、总结 前言 本笔记总结linux下使用gpio模拟spi时序的方法,基于arm64架构的一个SOC,linux内核版本为linux5.10.xxx,以驱动三线spi(时钟线sclk,片选cs,sdata数据读和写使用同一…

「二叉树进阶题解:构建、遍历与结构转化全解析」

文章目录 根据二叉树创建字符串思路代码 二叉树的层序遍历思路代码 二叉树的最近公共祖先思路代码 二叉搜索树与双向链表思路代码 从前序与中序遍历序列构造二叉树思路代码 总结 根据二叉树创建字符串 题目: 样例: 可以看见,唯一特殊的就…

SCI被「On Hold」意味着什么?会有哪些影响?

本文首发于“生态学者”微信公众号! 继Chemosphere在2023年7月被「On Hold」之后,昨晚Science of The Total Environment 被标记为「On Hold」状态在各大公众号和朋友圈被刷屏!(官方网址:https://mjl.clarivate.com/s…

PouchDB - 免费开源的 JavaScript 数据库,轻量易用,用于离线保存数据的场景

这个 JS 工具库可以让我们很容易地实现数据缓存到本地的需求,要写的代码量也很少。 PouchDB 是一个基于 JavaScript 语言开发的轻量级的数据库,可以在浏览器、Node.js 等环境中使用。作者是一位来自国外的女开发工程师 Alba Herreras。 这是一个运行在浏…

el-datepicker禁用未来日期(包含时分秒)type=‘datetime’

文章目录 实现代码方式1:当选中日期的时候去更新一次。方式2: 优化版本,使用 setTimout 每分钟更新一次。(防止选中日期之后过了很久再去选择时分秒时没有根据当前时间去改变) el-datepicker 选择器禁用未来日期,动态禁…

重生之“我打数据结构,真的假的?”--2.单链表(无习题)

C语言中的单链表总结 单链表是一种基础的数据结构,广泛应用于C语言编程中。它由节点组成,每个节点包含数据和指向下一个节点的指针。单链表的优点在于动态内存分配和高效的插入与删除操作。本文将详细探讨单链表的定义、基本操作、应用场景以及相关示例…

Gateway 统一网关

一、初识 Gateway 1. 为什么需要网关 我们所有的服务可以让任何请求访问,但有些业务不是对外公开的,这就需要用网关来统一替我们筛选请求,它就像是房间的一道门,想进入房间就必须经过门。而请求想要访问微服务,就必须…

ComfyUI系列——新手安装ComfyUI,就是这么简单

比较Midjoury、WebUI和ComfyUI 在了解ComfyUI的时候,还有其它两款类似的产品,于是就搜集了一下资料,以下是Midjoury、WebUI(通常指的是Stable Diffusion Web UI)和ComfyUI三者之间的异同点对比表。 特性MidjourneySt…

国内短剧系统源码搭建系统平台小程序新玩法

在数字化内容消费日益普及的今天,短剧小程序作为一种新兴的内容平台,其功能设计至关重要。一个好的短句系统不仅需要提供优质的内容展示,还需要具备一系列优秀功能以满足用户和运营者的需求。以下是一些必备的功能特点: 为大家介…

WebGL 添加背景图

1. 纹理坐标(st坐标)简介 ST纹理坐标(也称为UV坐标)是一种二维坐标系统,用于在三维模型的表面上精确地定位二维纹理图像。这种坐标系统通常将纹理的左下角映射到(0,0),而右上角映射到(1,1)。 S坐标&#x…

leetcode_128:最长连续序列

给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。 请你设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1: 输入:nums [100,4,200,1,3,2] 输出:4 解…

CSS揭秘:7. 伪随机背景

前置知识:CSS 渐变,5. 条纹背景,6. 复杂的背景图案 前言 本篇主要内容依然是关于背景的,无限平铺的背景会显得整齐美观,但又有些呆板,如何实现背景的多样性和随机性,是本篇的核心。 一、四种颜…

AI周报(10.20-10.26)

AI应用-牙科AI产品Pearl Pearl是一家致力于改善牙科患者护理的人工智能驱动型公司,推出了首款获得美国食品药品监督管理局(FDA)批准的人工智能,能够读取牙科X光片并即时识别疾病。今年7月获得5800万美元的B轮融资,以加…

GESP一级真题分析-202303-选择题1-输入输出设备、存储单位、默认数据类型、标识符命名

PDF文档回复:20241026 1 相关知识点 1) 输入输出设备 输入设备 是外界向计算机传送信息的装置。在微型计算机系统中,最常用的输入设备是键盘和鼠标。 此外还有电子光笔、数字化仪、图形扫描仪、触摸屏、麦克风、视频输入设备、条形码扫描等 输出设备 作用是将计…

Java-图书管理系统

我的个人主页 欢迎来到我的Java图书管理系统,接下来让我们一同探索如何书写图书管理系统吧! 1管理端和用户端 2建立相关的三个包(book、operation、user) 3建立程序入口Main类 4程序运行 1.首先图书馆管理系统分为管理员端和…

6.stm32 OLED显示屏

调试方式 串口调试:通过串口通信,将调试信息发送到电脑端,电脑使用串口助手显示调试信息 显示屏调试:直接将显示屏连接到单片机,将调试信息打印在显示屏上 Keil调试模式:借助Keil软件的调试模式&#…

【阅读笔记】Instruction-based Hypergraph Pretraining

Abstract中可以提炼的信息: 背景:预训练的作用是为了增强图学习模型将知识从大数据集转移到下游任务的适应性。 想解决的问题:训练目标的不同与数据分布的不同会阻碍预训练知识的迁移。 文章受到基于指令的提示词在语言模型训练广泛应用的启发…

Vue学习笔记(四)

事件处理 我们可以使用 v-on 指令 (通常缩写为 符号) 来监听 DOM 事件,并在触发事件时执行一些 JavaScript。用法为 v-on:click"methodName" 或使用快捷方式 click"methodName" 事件处理器的值可以是: 内联事件处理器&#xff1…