Elasticsearch-Filter DSL

Filter DSL

Elasticsearch中的所有的查询都会触发相关度得分的计算。对于那些我们不需要相关度得分的场景下,Elasticsearch以过滤器的形式提供了另一种查询功能,过滤器在概念上类似于查询,但是它们有非常快的执行速度,执行速度快主要有以下两个原因:

过滤器不会计算相关度的得分,所以它们在计算上更快一些。
过滤器可以被缓存到内存中,这使得在重复的搜索查询上,其要比相应的查询快出许多。

为了理解过滤器,可以将一个查询(像是match_all,match,bool等)和一个过滤器结合起来。我们以范围过滤器为例,它允许我们通过一个区间的值来过滤文档。这通常被用在数字和日期的过滤上。

下面这个例子使用一个被过滤的查询,其返回price值是在200到1000之间(闭区间)的书

POST /book/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match_all": {}
        }
      ],
      "filter": {
        "range": {
          "price": {
            "gte": 200,
            "lte": 1000
          }
        }
      }
    }
  }
}

POST /book/_search
{"query":{"match_all":{}}}

被过滤的查询包含一个match_all查询(查询部分)和一个过滤器(filter部分)。我们可以在查询部分中放入其他查询,在filter部分放入其它过滤器。在上面的应用场景中,由于所有的在这个范围之内的文档都是平等的(或者说相关度都是一样的),没有一个文档比另一个文档更相关,所以这个时候使用范围过滤器就非常合适了。通常情况下,要决定是使用过滤器还是使用查询,你就需要问自己是否需要相关度得分。如果相关度是不重要的,使用过滤器,否则使用查询。查询和过滤器在概念上类似于SELECT WHERE语句。

定位非法搜索及原因

在开发的时候,我们可能会写到上百行的查询语句,如果出错的话,找起来很麻烦,Elasticsearch提供了帮助开发人员定位不合法的查询的api _validate

  • 错误
GET /book/_search?explain
{
  "query": {
    "match1": {
      "name": "test"
    }
  }
}
  • 使用 validate
GET /book/_validate/query?explain
{
   "query": {
    "match1": {
      "name": "test"
    }
  }
}

{
“valid” : false,
“error” : “org.elasticsearch.common.ParsingException: no [query] registered for [match1]”
}

聚合分析

1.聚合介绍
聚合分析是数据库中重要的功能特性,完成对一个查询的数据集中数据的聚合计算,如:找出某字段(或计算表达式的结果)的最大值、最小值,计算和、平均值等。Elasticsearch作为搜索引擎兼数据库,同样提供了强大的聚合分析能力。
对一个数据集求最大、最小、和、平均值等指标的聚合,在ES中称为指标聚合 metric而关系型数据库中除了有聚合函数外,还可以对查询出的数据进行分组group by,再在组上进行指标聚合。在 ES 中group by 称为分桶,桶聚合 bucketing
Elasticsearch聚合分析语法
在查询请求体中以aggregations节点按如下语法定义聚合分析

aggregations" : {
"<aggregation_name>" : { <!--聚合的名字 -->
"<aggregation_type>" : { <!--聚合的类型 -->
<aggregation_body> <!--聚合体:对哪些字段进行聚合 -->
} [
,"meta" : { [<meta_data_body>] } ]? <!--元 -->
[,"aggregations" : { [<sub_aggregation>]+ } ]? <!--在聚合里面在定义子聚合 -
->
} [
,"<aggregation_name_2>" : { ... } ]*<!--聚合的名字 -->
}

aggregations 也可简写为 aggs

指标聚合

max min sum avg

示例一:查询所有书中最贵的


POST /book/_search
{
  "size": 0,
  "aggs": {
    "max_price": {
      "max": {
        "field": "price"
      }
    }
  }
}

{
“took” : 1,
“timed_out” : false,
“_shards” : {
“total” : 1,
“successful” : 1,
“skipped” : 0,
“failed” : 0
},
“hits” : {
“total” : {
“value” : 4,
“relation” : “eq”
},
“max_score” : null,
“hits” : [ ]
},
“aggregations” : {
“max_price” : {
“value” : 999.989990234375
}
}
}

  • 文档计数count
    示例: 统计price大于100的文档数量
POST /book/_search
{
  "query": {
     "range": {
       "price": {
         "gte": 100
       }
     }
  }
}
POST /book/_count
{
  "query": {
     "range": {
       "price": {
         "gt": 100
       }
     }
  }
}

{
“count” : 4,
“_shards” : {
“total” : 1,
“successful” : 1,
“skipped” : 0,
“failed” : 0
}
}

  • value_count 统计某字段有值的文档数
POST /book/_search?size=0
{
  "aggs": {
    "price_count": {
      "value_count": {
        "field": "price"
      }
    }
  }
}

{
“took” : 5,
“timed_out” : false,
“_shards” : {
“total” : 1,
“successful” : 1,
“skipped” : 0,
“failed” : 0
},
“hits” : {
“total” : {
“value” : 4,
“relation” : “eq”
},
“max_score” : null,
“hits” : [ ]
},
“aggregations” : {
“price_count” : {
“value” : 4
}
}
}

  • cardinality值去重计数 基数
POST /book/_search?size=0
{
  "aggs": {
    "_id_count": {
      "cardinality": {
        "field": "_id"
      }
    },
    "price_count": {
      "cardinality": {
        "field": "price"
      }
    }
  }
}
  • stats 统计 count max min avg sum 5个值

POST /book/_search?size=0
{
  "aggs": {
    "price_stats": {
      "stats": {
        "field": "price"
      }
    }
  }
}

{
“took” : 2,
“timed_out” : false,
“_shards” : {
“total” : 1,
“successful” : 1,
“skipped” : 0,
“failed” : 0
},
“hits” : {
“total” : {
“value” : 4,
“relation” : “eq”
},
“max_score” : null,
“hits” : [ ]
},
“aggregations” : {
“price_stats” : {
“count” : 4,
“min” : 100.44999694824219,
“max” : 999.989990234375,
“avg” : 510.3350028991699,
“sum” : 2041.3400115966797
}
}
}

  • xtended stats
    高级统计,比stats多4个统计结果: 平方和、方差、标准差、平均值加/减两个标准差的区间

POST /book/_search?size=0
{
  "aggs": {
    "price_stats": {
      "extended_stats": {
        "field": "price"
      }
    }
  }
}

{
“took” : 1,
“timed_out” : false,
“_shards” : {
“total” : 1,
“successful” : 1,
“skipped” : 0,
“failed” : 0
},
“hits” : {
“total” : {
“value” : 4,
“relation” : “eq”
},
“max_score” : null,
“hits” : [ ]
},
“aggregations” : {
“price_stats” : {
“count” : 4,
“min” : 100.44999694824219,
“max” : 999.989990234375,
“avg” : 510.3350028991699,
“sum” : 2041.3400115966797,
“sum_of_squares” : 1497716.610427039,
“variance” : 113987.33742266399,
“std_deviation” : 337.6201081432562,
“std_deviation_bounds” : {
“upper” : 1185.5752191856823,
“lower” : -164.90521338734243
}
}
}
}

  • Percentiles 占比百分位对应的值统计
POST /book/_search?size=0
{
  "aggs": {
    "price_percents": {
      "percentiles": {
        "field": "price"
      }
    }
  }
}

{
“took” : 40,
“timed_out” : false,
“_shards” : {
“total” : 1,
“successful” : 1,
“skipped” : 0,
“failed” : 0
},
“hits” : {
“total” : {
“value” : 4,
“relation” : “eq”
},
“max_score” : null,
“hits” : [ ]
},
“aggregations” : {
“price_percents” : {
“values” : {
“1.0” : 100.4499969482422,
“5.0” : 100.44999694824219,
“25.0” : 210.45000457763672,
“50.0” : 470.45001220703125,
“75.0” : 810.2200012207031,
“95.0” : 999.989990234375,
“99.0” : 999.989990234375
}
}
}
}

  • 指定分位值
POST /book/_search?size=0
{
  "aggs": {
    "price_percents": {
      "percentiles": {
        "field": "price",
        "percents" : [75, 99, 99.9]
      }
    }
  }
}

{
“took” : 1,
“timed_out” : false,
“_shards” : {
“total” : 1,
“successful” : 1,
“skipped” : 0,
“failed” : 0
},
“hits” : {
“total” : {
“value” : 4,
“relation” : “eq”
},
“max_score” : null,
“hits” : [ ]
},
“aggregations” : {
“price_percents” : {
“values” : {
“75.0” : 810.2200012207031,
“99.0” : 999.989990234375,
“99.9” : 999.989990234375
}
}
}
}

  • Percentiles rank 统计值小于等于指定值的文档占比
    统计price小于100和200的文档的占比
POST /book/_search?size=0
{
  "aggs": {
    "gge_perc_rank": {
      "percentile_ranks": {
        "field": "price",
        "values": [
          100,
          200
        ]
      }
    }
  }
}

{
“took” : 2,
“timed_out” : false,
“_shards” : {
“total” : 1,
“successful” : 1,
“skipped” : 0,
“failed” : 0
},
“hits” : {
“total” : {
“value” : 4,
“relation” : “eq”
},
“max_score” : null,
“hits” : [ ]
},
“aggregations” : {
“gge_perc_rank” : {
“values” : {
“100.0” : 12.448863986700994,
“200.0” : 23.81249956217682
}
}
}
}

  • 桶聚合
    https://www.elastic.co/guide/en/elasticsearch/reference/7.3/search-aggregations-bucket.html
    Bucket Aggregations,桶聚合。
    它执行的是对文档分组的操作(与sql中的group by类似),把满足相关特性的文档分到一个桶里,即
    桶分,输出结果往往是一个个包含多个文档的桶(一个桶就是一个group)
    bucket:一个数据分组
    metric:对一个数据分组执行的统计
POST /book/_search
{
  "size": 0,
  "aggs": {
    "group_by_price": {
      "range": {
        "field": "price",
        "ranges": [
          {
            "from": 0,
            "to": 200
          },
          {
            "from": 200,
            "to": 400
          },
          {
            "from": 400,
            "to": 1000
          }
        ]
      },
      "aggs": {
        "average_price": {
          "avg": {
            "field": "price"
          }
        }
      }
    }
  }
}

{
“took” : 1,
“timed_out” : false,
“_shards” : {
“total” : 1,
“successful” : 1,
“skipped” : 0,
“failed” : 0
},
“hits” : {
“total” : {
“value” : 4,
“relation” : “eq”
},
“max_score” : null,
“hits” : [ ]
},
“aggregations” : {
“group_by_price” : {
“buckets” : [
{
“key” : “0.0-200.0”,
“from” : 0.0,
“to” : 200.0,
“doc_count” : 1,
“average_price” : {
“value” : 100.44999694824219
}
},
{
“key” : “200.0-400.0”,
“from” : 200.0,
“to” : 400.0,
“doc_count” : 1,
“average_price” : {
“value” : 320.45001220703125
}
},
{
“key” : “400.0-1000.0”,
“from” : 400.0,
“to” : 1000.0,
“doc_count” : 2,
“average_price” : {
“value” : 810.2200012207031
}
}
]
}
}
}

  • 值的个数统计
"count_price": {
"value_count": {
"field": "price"
}
}
  • 实现having 效果
POST /book/_search
{
  "size": 0,
  "aggs": {
    "group_by_price": {
      "range": {
        "field": "price",
        "ranges": [
          {
            "from": 0,
            "to": 200
          },
          {
            "from": 200,
            "to": 400
          },
          {
            "from": 400,
            "to": 1000
          }
        ]
      },
      "aggs": {
        "average_price": {
          "avg": {
            "field": "price"
          }
        },
        "having": {
          "bucket_selector": {
            "buckets_path": {
              "avg_price": "average_price"
            },
            "script": {
              "source": "params.avg_price >= 200 "
            }
          }
        }
      }
    }
  }
}

{
“took” : 66,
“timed_out” : false,
“_shards” : {
“total” : 1,
“successful” : 1,
“skipped” : 0,
“failed” : 0
},
“hits” : {
“total” : {
“value” : 4,
“relation” : “eq”
},
“max_score” : null,
“hits” : [ ]
},
“aggregations” : {
“group_by_price” : {
“buckets” : [
{
“key” : “200.0-400.0”,
“from” : 200.0,
“to” : 400.0,
“doc_count” : 1,
“average_price” : {
“value” : 320.45001220703125
}
},
{
“key” : “400.0-1000.0”,
“from” : 400.0,
“to” : 1000.0,
“doc_count” : 2,
“average_price” : {
“value” : 810.2200012207031
}
}
]
}
}
}

上一篇:使用switch表达式简化switch语句


下一篇:RFC9000中文文档 StreamState