Elasticsearch 中的高效按位匹配

devtools/2024/10/23 12:02:08/

作者:来自 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.ppmy.cn/devtools/128149.html

相关文章

CSS基础—网页布局(重点!)

1、两列布局 (1)概念 经典两列布局是指一种网页布局方式,其中一列宽度固定,另一列宽度自适应。‌ 这种布局方式在网页设计中非常常见,因为它能够提供良好的视觉效果和用户体验。 如图所示: 页面顶部放置一…

002_基于django国内运动男装小红书文章数据可视化分析系统的设计与实现2024_qo6cy3i4

目录 系统展示 开发背景 代码实现 项目案例 获取源码 博主介绍:CodeMentor毕业设计领航者、全网关注者30W群落,InfoQ特邀专栏作家、技术博客领航者、InfoQ新星培育计划导师、Web开发领域杰出贡献者,博客领航之星、开发者头条/腾讯云/AW…

如何彻底销毁硬盘数据

今天分享的是针对硬盘有重要数据,但是损坏了,或者没损坏,但是怕数据泄露的办法 软件销毁方法 多次重写:通过格式化硬盘并多次写入无用数据来覆盖原有数据。使用专用软件:如File Shredder或DoYourData Super Eraser&a…

盘古信息诚邀您莅临2024亚洲电子展,共赴电子盛宴

作为具有广泛影响力的电子制造专业展会,2024 NEPCON ASIA亚洲电子展将于2024年11月6日至8日在深圳国际会展中心(宝安)举办。此次展会旨在打造一站式电子制造产业全生态链,帮助国内外全品类电子生产企业优化供应链,实现…

IDEA如何查看所有的断点(Breakpoints)并关闭

前言 我们在使用IDEA开发Java应用时,基本上都需要进行打断点的操作,这方便我们排查BUG,也方便我们查看设计的是否正确。 不过有时候,我们不希望进入断点,这时候除了点击断点关闭外,有没有更快速的方便关闭…

Python语法基础:复数

文章目录 一、复数的定义二、复数的创建三、复数的操作1. 算术运算2. 类型转换3. 数学函数 Python语法基础:复数 在编程中,除了处理常见的整数和浮点数外,经常还会遇到需要处理复数的场景。复数在数学和工程领域有着广泛的应用,特…

Recall(召回率)、F1分数、特异性(specificity)和精确度(precision)

在机器学习和统计学中,recall(召回率)、F1分数、特异性(specificity)和精确度(precision)是评估分类模型性能的常用指标。下面是每个指标的定义和它们在二分类问题中的应用: 召回率&…

【Ubuntu】Virtualbox下lamp集群分布式搭建Wordpress

WordPress是一种使用PHP语言开发的开源内容管理系统(CMS),也常被用作博客平台。 开发语言:PHP 数据库:MySQL、mariadb(或其他兼容的数据库系统) 授权方式:GNU通用公共许可证下发布&a…