自学内容网 自学内容网

elasticsearch 使用Painless脚本

1. 创建索引

首先,我们可以创建一个包含适当字段的 products 索引,并定义字段的映射(mapping)。例如,我们可以使用 text 类型来存储产品名称,keyword 类型来存储分类,floatdouble 类型来存储价格、评分和折扣。

PUT /products
{
  "mappings": {
    "properties": {
      "product_name": {
        "type": "text"
      },
      "price": {
        "type": "float"
      },
      "category": {
        "type": "keyword"
      },
      "rating": {
        "type": "float"
      },
      "discount": {
        "type": "float"
      },
      "availability": {
        "type": "boolean"
      },
      "stock": {
        "type": "integer"
      },
      "release_date": {
        "type": "date"
      }
    }
  }
}

2. 插入模拟数据

接下来,我们插入一些模拟产品数据到 products 索引。以下是一些数据样本:

POST /products/_doc/1
{
  "product_name": "Apple iPhone 15",
  "price": 999.99,
  "category": "Smartphones",
  "rating": 4.5,
  "discount": 0.1,
  "availability": true,
  "stock": 50,
  "release_date": "2023-09-01"
}

POST /products/_doc/2
{
  "product_name": "Samsung Galaxy S24",
  "price": 899.99,
  "category": "Smartphones",
  "rating": 4.3,
  "discount": 0.05,
  "availability": true,
  "stock": 30,
  "release_date": "2023-10-10"
}

POST /products/_doc/3
{
  "product_name": "Dell XPS 13",
  "price": 1199.99,
  "category": "Laptops",
  "rating": 4.8,
  "discount": 0.15,
  "availability": true,
  "stock": 20,
  "release_date": "2023-08-20"
}

POST /products/_doc/4
{
  "product_name": "Sony WH-1000XM5",
  "price": 349.99,
  "category": "Headphones",
  "rating": 4.7,
  "discount": 0.2,
  "availability": false,
  "stock": 0,
  "release_date": "2023-06-15"
}

POST /products/_doc/5
{
  "product_name": "Apple MacBook Air",
  "price": 999.00,
  "category": "Laptops",
  "rating": 4.6,
  "discount": 0.1,
  "availability": true,
  "stock": 15,
  "release_date": "2023-11-01"
}

POST /products/_doc/6
{
  "product_name": "Fitbit Charge 5",
  "price": 149.99,
  "category": "Wearables",
  "rating": 4.4,
  "discount": 0.05,
  "availability": true,
  "stock": 80,
  "release_date": "2023-07-10"
}

在 Elasticsearch 中,Painless 是一种用于查询和聚合操作的内置脚本语言。它被设计为高效、安全、且易于使用的脚本语言,用于在 Elasticsearch 中执行动态计算。Painless 可以在许多不同的场景中使用,比如在 查询过滤器聚合文档更新排序脚本字段 等操作中动态计算值。

Painless 脚本的基本特点:

  • 高效:Painless 脚本会经过优化,执行速度较快。
  • 安全:Painless 会在执行过程中检查潜在的安全问题,防止执行恶意代码。
  • 易用:语法简洁,类似于 Java,但也有一些简化和限制。

Painless 脚本的常见用途

  1. 脚本查询和过滤
  2. 脚本字段
  3. 聚合中的脚本
  4. 文档更新
  5. 排序

1. 脚本查询和过滤

你可以使用 Painless 脚本来动态计算查询条件。例如,假设你要查询文档中的字段 price 是否大于某个动态值:

示例:基于脚本的查询
POST /products/_search
{
  "query": {
    "script_score": {
      "query": {
        "match_all": {}
      },
      "script": {
        "source": "doc['price'].value > params.threshold ? 1 : 0",
        "params": {
          "threshold": 1000
        }
      }
    }
  }
}

在这个查询中,script_score 根据 price 字段的值与 threshold 参数进行比较,只有当 price > 1000 时,文档才会匹配查询。
在这里插入图片描述

2. 脚本字段

Painless 脚本可以用于计算查询结果中的 脚本字段,允许你在查询结果中添加基于其他字段计算的动态值。

示例:脚本字段

假设每个文档都有 pricetax 字段,你想在查询结果中计算每个文档的总价(price + tax)。

POST /products/_search
{
  "query": {
    "match_all": {}
  },
  "script_fields": {
    "total_price": {
      "script": {
        "lang": "painless",
        "source": "doc['price'].value + doc['discount'].value"
      }
    }
  }
}

这将为每个文档添加一个名为 total_price 的字段,字段值是 price + discount 的和。

在这里插入图片描述

3. 聚合中的脚本

Painless 脚本还可以用在聚合操作中,用于对字段值进行动态计算。例如,基于某个条件计算总和或平均值。

示例:脚本聚合

假设你想计算所有产品的 price 字段的加权平均值,其中权重来自于另一个字段 rating

POST /products/_search
{
  "size": 0,
  "aggs": {
    "weighted_avg_price": {
      "avg": {
        "script": {
          "lang": "painless",
          "source": "doc['price'].value * doc['rating'].value"
        }
      }
    }
  }
}

在这个例子中,weighted_avg_price 聚合会计算 price * rating 的平均值。
在这里插入图片描述

4. 文档更新中的脚本

Painless 脚本可以用来动态更新文档中的字段。这在批量更新或修改文档时非常有用,特别是当更新的内容需要基于现有字段的值进行计算时。

示例:文档更新

假设你有一个文档中存储了 pricediscount 字段,现在你想要根据 discount 更新 price

POST /products/_update/1
{
  "script": {
    "lang": "painless",
    "source": "ctx._source.price = ctx._source.price - (ctx._source.price * ctx._source.discount)"
  }
}

在这个例子中,price 字段会根据 discount 字段的值进行折扣更新。
在这里插入图片描述

5. 排序中的脚本

你可以使用 Painless 脚本对搜索结果进行动态排序。例如,假设你要根据一个计算出来的值进行排序,而这个值是由多个字段计算得出的。

示例:脚本排序

假设你有 ratingprice 字段,你想按照 rating 除以 price 的结果对文档进行排序:

POST /products/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "_script": {
        "type": "number",
        "script": {
          "lang": "painless",
          "source": "doc['rating'].value / doc['price'].value"
        },
        "order": "desc"
      }
    }
  ],
  "script_fields": {
    "rating_to_price_ratio": {
      "script": {
        "lang": "painless",
        "source": "doc['rating'].value / doc['price'].value"
      }
    }
  }
}

在这个例子中,文档将按照 rating / price 的值进行降序排序。

在这里插入图片描述


Painless 脚本的常见用法和注意事项

1. 访问字段

在 Painless 中,你可以使用 doc['field_name'].value 来访问字段的值。如果字段是多值字段,你可以使用 doc['field_name'].values 来获取所有的值。

  • 对于文本字段:doc['text_field'].value 返回的是字段的一个值(如果该字段为多值字段,Painless 默认取第一个值)。
  • 对于数字字段:可以像上面的示例那样直接访问数字字段。
2. 参数传递

你可以通过 params 来传递外部参数到脚本中,这样就能在脚本中动态使用这些值。

{
  "query": {
    "range": {
      "price": {
        "gte": "{{params.min_price}}"
      }
    }
  },
  "params": {
    "min_price": 100
  }
}

在这里,params.min_price 是传递给脚本的参数。

3. 条件判断

Painless 支持基本的条件判断,比如 if 语句。可以用来执行基于条件的计算。

{
  "script": {
    "lang": "painless",
    "source": """
      if (doc['discount'].size() != 0) {
        return doc['price'].value - (doc['price'].value * doc['discount'].value);
      } else {
        return doc['price'].value;
      }
    """
  }
}

这个脚本判断如果 discount 字段存在,就对 price 进行折扣计算,否则返回原价。

4. 限制
  • 性能:虽然 Painless 被设计成高效的,但大量的动态计算会对性能产生一定的影响。尽量避免在查询或聚合中使用过于复杂的脚本,尤其是在大规模数据集上。
  • 沙盒环境:Painless 是运行在沙盒环境中的,意味着它的功能被严格限制,无法进行一些危险的操作,如文件操作、网络请求等。
5. 调试脚本

Painless 脚本支持调试输出,可以在开发时利用 _explain 或者调试日志来查看脚本的执行情况。

总结

Painless 是 Elasticsearch 中强大且高效的脚本语言,广泛应用于查询、更新、聚合、排序等多种操作。通过使用 Painless 脚本,开发者可以对 Elasticsearch 的行为进行细粒度的控制和动态计算,从而实现更灵活的功能。

在实际应用中,合理使用 Painless 脚本能够帮助解决复杂的数据计算需求,但也需要注意性能和安全性,避免过度使用脚本影响集群性能。


原文地址:https://blog.csdn.net/qq_37362891/article/details/144453289

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!