是否可以在Elasticseach Painless脚本中转换JSON数据并对其执行进一步的操作?

时间:2019-05-26 12:34:10

标签: elasticsearch elasticsearch-painless

我们有大量JSON格式的文档供您搜索,以查找模式和历史趋势。 Elasticsearch似乎非常适合解决此问题。第一个技巧是文档是成千上万个“嵌套”文档(带有标题)的集合。第二个技巧是,这些嵌套文档表示具有不同类型的数据。

为了适应这一点,所有的value字段都被“编码”为字符串数组,因此在JSON中将单个整数值存储为“ [\“ 1 \”]“,并在其中存储了floats被展平为“ [\” 123.45 \“,\” 678.9 \“,...]”,依此类推。 (我们还有一些字符串数组,不需要转换。)虽然这很尴尬,但考虑到Elasticsearch中涉及的所有其他功能似乎都可以正常工作,我本来会认为这是一个不错的妥协。

这里的特殊问题是这些存储的数据值可能表示一个位域,我们可能需要从中检查一位的状态。由于此字段将存储为单元素字符串数组,例如“ [\“ 14657 \”],因此我们需要将其转换为单个整数,然后将其多次移位到所需的位(或应用遮罩(如果有此功能可用)。

我发现使用Elasticsearch可以嵌入“无痛”脚本,但是示例各不相同,而且我找不到能够说明如何将任意长度的字符串数组数据字段转换为适当类型的脚本,进一步比较。这是我的查询脚本。

{
  "_source" : false,
  "from" : 0, "size" : 10,
  "query": {
    "nested": {
      "path": "Variables",
      "query": {
        "bool": {
          "must": {
            "match": {"Variables.Designation": "Big_Long_Variable_Name"}
          },
          "must_not": {
            "match": {"Variables.Data": "[0]"}
          },
          "filter": {
            "script": {
              "script": {
                "source":
                "
                  def vals = doc['Variables.Data'];
                  return vals[0] != params.setting;
                ",
                "params": {
                  "setting": 3
                }
              }
            }
          }
        }
      },
      "inner_hits": {
        "_source": "Variables.Data"
      }
    }
  }
}

我需要以某种方式将vals变量转换为一个整数数组,选择第一个值,进行一些位运算,然后进行比较以返回true或false。在此示例中,我希望能够将“设置”设置为等于要检查开/关的位位置。

我已经完成了Elasticsearch的练习,发现我需要将Variables.Data字段设置为关键字,以便可以搜索其中的特定值。我意识到这已经脱离了Elasticsearch的意图,但是出于其他原因,我仍然认为这可能是最好的解决方案。我创建了一个新索引,然后重新导入了我的测试文档,索引大小增加了约30%。如果我可以解决这个问题,那就是我愿意做出的妥协。

我在Painless中有哪些工具可以完成这项工作? (或者,我为使用此工具尝试这样做而疯狂吗?)

1 个答案:

答案 0 :(得分:0)

我建议您尽可能(甚至在没有可能的情况下)使用Elasticsearch提供的类型对数据进行编码,以最大程度地发挥作用。例如,对于位字符串,您可以将它们编码为1和0的数组,以简化Painless的操作。

我认为,无痛仍然是原始的。很难调试。很难读。很难维护。而且,在Painless中具有大型功能是一个可怕的想法。

要回答您的问题,您基本上需要轻松地解析数组字符串,并将其放入可用的数据类型之一中,以便进行所需的比较。例如,对于列表,您将使用类似split函数的方法,然后将结果中的每个项目手动设置为int,float,string等。

在将其添加到脚本字段之前,请使用execute API测试少量位:

POST /_scripts/painless/_execute
{
  "script": {
    "source": """
    ArrayList arr = []; //to start with
    // use arr.add(INDEX, VALUE) to add after parsing
    """,
    "params": {
      "foo": 100.0,
      "bar": 1000.0
    }
  }
}

另一方面,如果您将数据保存在ElasticSearch提供的数据类型中(请注意,ElasticSearch支持在文档内部保存列表),那么在Painless中该任务将容易得多。

例如,与其将my_doc.foo =“ [\” 123.45 \“,\” 678.9 \“,...]”作为以后要解析的字符串,为什么不将其另存为本机浮点列表而是像my_doc.foo = [123.45,678.9,...]吗?

这样,您可以避免解析文本文档所需的不必要的无痛代码。