前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >打造高效物联网数据处理:Elasticsearch中的六种按位匹配方法

打造高效物联网数据处理:Elasticsearch中的六种按位匹配方法

原创
作者头像
点火三周
发布2024-10-28 17:50:47
发布2024-10-28 17:50:47
10800
代码可运行
举报
文章被收录于专栏:Elastic Stack专栏Elastic Stack专栏
运行总次数:0
代码可运行

介绍

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

截至本文撰写时,Elasticsearch 尚未有原生的按位匹配操作符,而 Lucene 也未直接支持按位匹配。为了解决这个限制,本文介绍了在 Elasticsearch 中进行二进制编码和按位匹配的六种方法:术语编码(我偏爱的方式)、布尔编码、稀疏位位置编码、精确匹配的整数编码、脚本化按位匹配的整数编码和使用 ESQL 进行按位匹配的整数编码。

术语编码

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

术语编码的优点

术语编码方法允许 Elasticsearch 利用优化的数据结构,即使对于大型数据集也能进行高效查询。此外,这种方法在需要频繁查询不同组合的位时扩展性很好,因为每个位被视为一个独立的实体,可以被索引和搜索。

术语编码的缺点

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

设置术语编码的环境

定义关键字表示的映射:

代码语言:javascript
代码运行次数:0
复制
PUT test_terms_encoding
{
  "mappings": {
    "properties": {
      "terms_encoded_bits": {
        "type": "keyword"
      }
    }
  }
}

使用术语编码索引文档

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

代码语言:javascript
代码运行次数:0
复制
POST test_terms_encoding/_doc/1
{
  "terms_encoded_bits": ["b3=0", "b2=1", "b1=1", "b0=0"] // 二进制 0110
}
代码语言:javascript
代码运行次数:0
复制
POST test_terms_encoding/_doc/2
{
  "terms_encoded_bits": ["b3=1", "b2=0", "b1=1", "b0=0"] // 二进制 1010
}

使用术语编码查询

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

代码语言:javascript
代码运行次数:0
复制
GET test_terms_encoding/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "terms_encoded_bits": "b3=1"
          }
        },
        {
          "term": {
            "terms_encoded_bits": "b0=0"
          }
        }
      ]
    }
  }
}

布尔编码

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

布尔编码的优点

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

布尔编码的缺点

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

设置布尔编码的环境

定义布尔字段的映射:

代码语言:javascript
代码运行次数:0
复制
PUT test_boolean_encoding
{
  "mappings": {
    "properties": {
      "b3": { "type": "boolean" },
      "b2": { "type": "boolean" },
      "b1": { "type": "boolean" },
      "b0": { "type": "boolean" }
    }
  }
}

使用布尔编码索引文档

为每个位索引布尔值的文档:

代码语言:javascript
代码运行次数:0
复制
POST test_boolean_encoding/_doc/1
{
  "b3": false,
  "b2": true,
  "b1": true,
  "b0": false
} // 二进制 0110 – 整数 6
代码语言:javascript
代码运行次数:0
复制
POST test_boolean_encoding/_doc/2
{
  "b3": true,
  "b2": false,
  "b1": true,
  "b0": false
} // 二进制 1010 – 整数 10

使用布尔编码查询

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

代码语言:javascript
代码运行次数:0
复制
GET test_boolean_encoding/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "b3": true
          }
        },
        {
          "term": {
            "b0": false
          }
        }
      ]
    }
  }
}

稀疏位位置编码

这种方法只编码数组中设置为 true 的位的位置。

稀疏位位置编码的优点

如果大多数文档通常没有任何位设置为 true,这种方法在存储方面可能比前面的方法更高效。例如,可以想象位表示警告标志的数据集,这些标志很少为 true,这将导致稀疏位位置编码数组为空(因此节省空间)。

稀疏位位置编码的缺点

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

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

定义整数数组的映射:

代码语言:javascript
代码运行次数:0
复制
PUT test_sparse_encoding
{
  "mappings": {
    "properties": {
      "sparse_bit_positions": {
        "type": "integer"
      }
    }
  }
}

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

将位的位置编码为整数的文档索引:

代码语言:javascript
代码运行次数:0
复制
POST test_sparse_encoding/_doc/1
{
  "sparse_bit_positions": [2, 1] // 二进制 0110
}
代码语言:javascript
代码运行次数:0
复制
POST test_sparse_encoding/_doc/2
{
  "sparse_bit_positions": [3, 1] // 二进制 1010
}

使用稀疏位位置编码查询

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

代码语言:javascript
代码运行次数:0
复制
GET test_sparse_encoding/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "sparse_bit_positions": 3
          }
        }
      ],
      "must_not": [
        {
          "term": {
            "sparse_bit_positions": 0
          }
        }
      ]
    }
  }
}

精确匹配的整数编码

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

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

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

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

这种方法仅讨论表示二进制序列的整数值的精确匹配。它不涉及整数内的按位匹配。这也要求在将二进制值存储到 Elasticsearch 之前将其转换为整数。

设置整数编码的环境

定义整数编码的映射:

代码语言:javascript
代码运行次数:0
复制
PUT test_integer_encoding
{
  "mappings": {
    "properties": {
      "integer_representation": {
        "type": "integer"
      }
    }
  }
}

使用整数编码索引文档

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

代码语言:javascript
代码运行次数:0
复制
POST test_integer_encoding/_doc/1
{
  "integer_representation": 6  // 二进制 0110
}
代码语言:javascript
代码运行次数:0
复制
POST test_integer_encoding/_doc/2
{
  "integer_representation": 10 // 二进制 1010
}

使用整数编码查询

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

代码语言:javascript
代码运行次数:0
复制
GET test_integer_encoding/_search
{
  "query": {
    "term": {
      "integer_representation": 6 // 二进制 0110
    }
  }
}

脚本化按位匹配的整数编码

在这种方法中,我们扩展了将二进制值编码为整数的概念,并利用 脚本化查询 功能查询整数值中的特定位。本文介绍这种方法是为了完整性,但请记住,广泛使用脚本化查询会给集群带来额外的工作负载,并可能比其他方法更慢和更低效。

脚本化按位匹配的整数编码的优点

这种方法具有“精确匹配的整数编码”方法的优点。额外的优点是可以匹配特定位。

脚本化按位匹配的整数编码的缺点

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

设置和索引文档

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

查询

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

代码语言:javascript
代码运行次数:0
复制
GET test_integer_encoding/_search
{
  "query": {
    "bool": {
      "filter": {
        "script": {
          "script": {
            "source": """
            // b3 为真
            // 即 "integer_representation" AND 1000 == 1000
            // 请记住 1000 二进制 == 8 整数
            ((doc['integer_representation'].value & 8) == 8) &&
            // b0 为假
            // 即 "integer_representation" AND 0001 == 0
            ((doc['integer_representation'].value & 1) == 0)
            """
          }
        }
      }
    }
  }
}

使用 ESQL 进行按位匹配的整数编码

与“脚本化按位匹配的整数编码”方法类似,这种方法也可以匹配特定位,但它利用 ESQL 而不是脚本化查询。本文介绍这种方法是为了完整性,但广泛使用这种方法可能会给集群带来额外的工作负载,并可能比其他方法更慢和更低效。

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

这种方法具有“脚本化按位匹配的整数编码”的优点。额外的优点是它利用了 ESQL,ESQL 设计时考虑了性能。

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

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

设置和索引文档

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

查询

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

代码语言:javascript
代码运行次数:0
复制
POST /_query?format=txt
{
  "query": """
  FROM test_integer_encoding
  METADATA _index, _id
  // 使用除法将我们感兴趣的位右移
  // 即除以 8(或 b1000 - 对应 b3)
  // 将 b3 移动到最低有效位位置,即 b0
  // 此外,右边的位被丢弃
  // 然后模 2 检查新的(移位后)b0(原来是 b3)的值是奇数还是偶数(1 或 0)
  | WHERE (integer_representation / 8 % 2 == 1)  // b3 为真
  | WHERE (integer_representation / 1 % 2 == 0)  // b0 为假
  | KEEP _id, integer_representation
  """
}

结论

在本文中,我们探讨了六种按位匹配的方法——术语编码(我偏爱的方式)、布尔编码、稀疏位位置编码、精确匹配的整数编码、脚本化按位匹配的整数编码和使用 ESQL 进行按位匹配的整数编码。展示了如何应用不同的方法在 Elasticsearch 中高效处理按位匹配。每种方法都有其优点和权衡,具体取决于您的应用需求。

对于需要匹配个别位的场景,基于术语和布尔字段的方法效果良好且高效。将 true 位位置表示为整数数组提供了一种紧凑且灵活的解决方案,适用于稀疏位序列。将二进制序列编码为整数可能适合整个序列操作,但代价是失去了高效查询个别位的能力。我们还可以使用脚本化查询或 ESQL 在整数中查询个别位,但这些方法可能比其他方法效率低。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
  • 术语编码
    • 术语编码的优点
    • 术语编码的缺点
    • 设置术语编码的环境
    • 使用术语编码索引文档
    • 使用术语编码查询
  • 布尔编码
    • 布尔编码的优点
    • 布尔编码的缺点
    • 设置布尔编码的环境
    • 使用布尔编码索引文档
    • 使用布尔编码查询
  • 稀疏位位置编码
    • 稀疏位位置编码的优点
    • 稀疏位位置编码的缺点
    • 设置稀疏位位置编码的环境
    • 使用稀疏位位置编码索引文档
    • 使用稀疏位位置编码查询
  • 精确匹配的整数编码
    • 精确匹配的整数编码的优点
    • 精确匹配的整数编码的缺点
    • 设置整数编码的环境
    • 使用整数编码索引文档
    • 使用整数编码查询
  • 脚本化按位匹配的整数编码
    • 脚本化按位匹配的整数编码的优点
    • 脚本化按位匹配的整数编码的缺点
    • 设置和索引文档
    • 查询
  • 使用 ESQL 进行按位匹配的整数编码
    • 使用 ESQL 进行按位匹配的整数编码的优点
    • 使用 ESQL 进行按位匹配的整数编码的缺点
    • 设置和索引文档
    • 查询
  • 结论
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档