提问:布和纸怕什么?

社区日报 第744期 (2019-09-30)

1.基于spark集群的券商个性化推荐系统架构设计最佳实践;
http://1t.click/a2mv
2.图辅助的搜索;
http://1t.click/a2mw
3.k8s nginx ingress日志收集;
http://1t.click/a2mx

PS:举国欢庆,大家快乐;国庆后见~~
编辑:wt
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
继续阅读 »
1.基于spark集群的券商个性化推荐系统架构设计最佳实践;
http://1t.click/a2mv
2.图辅助的搜索;
http://1t.click/a2mw
3.k8s nginx ingress日志收集;
http://1t.click/a2mx

PS:举国欢庆,大家快乐;国庆后见~~
编辑:wt
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub 收起阅读 »

社区日报 第743期 (2019-09-29)

1.Logstash教程:快速入门指南。
https://tinyurl.com/y6gb3sen
2.X-Pack替代方案比较。
https://tinyurl.com/y8andhyf
3.(自备梯子)非洲正在建立一个不像硅谷的人工智能行业。
https://tinyurl.com/yxfwsk7v

线上活动:
1.10月16日,ELK初学者入门
http://1t.click/aywj
2.10月30日,Elastic SIEM实操网络研讨会
http://1t.click/ayxu

Elastic Meetingup:
1.10月25日,Elastic教育行业分享会
http://1t.click/aywm

编辑:至尊宝
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup
继续阅读 »
1.Logstash教程:快速入门指南。
https://tinyurl.com/y6gb3sen
2.X-Pack替代方案比较。
https://tinyurl.com/y8andhyf
3.(自备梯子)非洲正在建立一个不像硅谷的人工智能行业。
https://tinyurl.com/yxfwsk7v

线上活动:
1.10月16日,ELK初学者入门
http://1t.click/aywj
2.10月30日,Elastic SIEM实操网络研讨会
http://1t.click/ayxu

Elastic Meetingup:
1.10月25日,Elastic教育行业分享会
http://1t.click/aywm

编辑:至尊宝
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup 收起阅读 »

社区日报 第742期 (2019-09-28)

1.ES写报错的解决方法 http://t.cn/Ain8Bv55 2.腾讯对ES进行写优化的步骤 http://t.cn/Ain8Bv5V 3.Elasticsearch X-Pack 系列之 Machine Learning 解析 http://t.cn/Ain8Bv5b

继续阅读 »

1.ES写报错的解决方法 http://t.cn/Ain8Bv55 2.腾讯对ES进行写优化的步骤 http://t.cn/Ain8Bv5V 3.Elasticsearch X-Pack 系列之 Machine Learning 解析 http://t.cn/Ain8Bv5b

收起阅读 »

社区日报 第741期 (2019-09-27)


1、开源:Elasticsearch Site&App Search PHP 客户端1.0发布
https://tinyurl.com/yxw9zoku
2、Elasticsearch实时数据监控实战
https://tinyurl.com/y2s2gk7q
3、视频:Elasticsearch集群性能的5个基础认知
https://tinyurl.com/y48vcr9a

编辑:铭毅天下
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup 
继续阅读 »

1、开源:Elasticsearch Site&App Search PHP 客户端1.0发布
https://tinyurl.com/yxw9zoku
2、Elasticsearch实时数据监控实战
https://tinyurl.com/y2s2gk7q
3、视频:Elasticsearch集群性能的5个基础认知
https://tinyurl.com/y48vcr9a

编辑:铭毅天下
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup  收起阅读 »

社区日报 第740期 (2019-09-26)

1、如何基于 Kibana 进行数据探索和机器学习实践
http://tinyurl.com/y2j3vthx
2、Kibana analyze api ui 升级到最新 7.3 版本
http://tinyurl.com/y3s64klj
3、Elastic Cloud On Kubernetes 介绍
http://tinyurl.com/y2sx2f4z

编辑:rockybean
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup
继续阅读 »
1、如何基于 Kibana 进行数据探索和机器学习实践
http://tinyurl.com/y2j3vthx
2、Kibana analyze api ui 升级到最新 7.3 版本
http://tinyurl.com/y3s64klj
3、Elastic Cloud On Kubernetes 介绍
http://tinyurl.com/y2sx2f4z

编辑:rockybean
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup 收起阅读 »

社区日报 第739期 (2019-09-25)

1、基于 ElasticStack 实现 Mulesoft 的可观察性
https://tinyurl.com/yy7xwe3c
2、Elasticsearch 7.3 新功能 DataFrame 实战演练
https://tinyurl.com/yxqgxsdz
3、Elastic 在金融领域的发展和应用趋势探讨
https://tinyurl.com/y5fufsy7


编辑:rockybean
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup
继续阅读 »
1、基于 ElasticStack 实现 Mulesoft 的可观察性
https://tinyurl.com/yy7xwe3c
2、Elasticsearch 7.3 新功能 DataFrame 实战演练
https://tinyurl.com/yxqgxsdz
3、Elastic 在金融领域的发展和应用趋势探讨
https://tinyurl.com/y5fufsy7


编辑:rockybean
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup 收起阅读 »

社区日报 第738期 (2019-09-24)

1、Elasticsearch高级调优方法论之——根治慢查询!
http://1t.click/ausC
2、Elasticsearch高并发写入优化的开源协同经历。
http://1t.click/ausD
3、Elasticsearch由浅入深(十一)内核原理。
http://1t.click/ausE



编辑:叮咚光军

归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup
继续阅读 »
1、Elasticsearch高级调优方法论之——根治慢查询!
http://1t.click/ausC
2、Elasticsearch高并发写入优化的开源协同经历。
http://1t.click/ausD
3、Elasticsearch由浅入深(十一)内核原理。
http://1t.click/ausE



编辑:叮咚光军

归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup 收起阅读 »

聚合元数据——对聚合结果进行打标签

背景

在我们的项目中需要对聚合后的结果进行二次的terms的聚合。实际需求就是有n个模型,需要统计每个模型在每段时间的调用次数,然后需要查询指定m个模型的调用总次数。我们要为每个模型建立一个索引,然后为每个模型查一次这段时间内的使用次数。

注:我们记录的值只能从结果中拿取。

实现过程

第一次设计

每个模型在第一次设计的时候是两个字段,【调用次数】、【错误次数】,使用以下语句:

{
  "aggs": {
    "error": {
      "filters": {
        "filters": {
          "error": {
            "query_string": {
              "query": "state:-1",
              "analyze_wildcard": true,
              "default_field": "*"
            }
          }
        }
      }
    }
  },
  "size": 0,
  "query": {
    "bool": {
      "must": [
        {
          "bool": {
            "should": [
              {
                "match_phrase": {
                  "li": "D003" //说明这是一次模型调用
                }
              }
            ],
            "minimum_should_match": 1
          }
        },
        {
          "match_phrase": {
            "modelId..keyword": {
              "query": "modelId01"
            }
          }
        },
        {
          "range": {
            "x_st": {
              "gte": "now/h-1h-10s",
              "lte": "now/h-10s",
              "format": "epoch_millis"
            }
          }
        }
      ]
    }
  }
}

结果为:

{
  "took" : 215,
  "timed_out" : false,
  "_shards" : {
    "total" : 1095,
    "successful" : 1095,
    "skipped" : 1053,
    "failed" : 0
  },
  "hits" : {
    "total" : 0,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "aggregations" : {
    "error" : {
      "buckets" : {
        "error" : {
          "doc_count" : 0
        }
      }
    }
  }
}

解析后保存:

{"@timestamp":"2019-09-23T12:23:23.333","count":0,"error":0}

这种情况可以统计每个模型在某段时间内的调用次数,使用索引名来区分每个model。但是在统计指定m个模型的时候就不行了,使用索引名来查询的时候由于是指定m个,前缀不能使用* 匹配,并且不能罗列所有m个索引来查询,就无法达到统计的效果。 第一次设计因为不能在结果中记录模型ID导致不能统计指定的m个模型的数量,以失败告终。

第二次设计

既然需要在统计结果中记录模型ID,那就使用terms聚合来进行操作,先使用模型ID过滤一下数据,然后使用聚合唯一的模型ID,这样就有了模型ID。查询语句如下:

{
  "aggs": {
    "modelId": {
      "terms": {
        "field": "modelId.keyword",
        "size": 5,
        "order": {
          "_count": "desc"
        }
      }
    }
  },
  "size": 0,
  "query": {
    "bool": {
      "must": [
        {
          "match_phrase": {
            "modelId.keyword": {
              "query": "modelId01"
            }
          }
        },
        {
          "range": {
            "x_st": {
              "gte": "now/h-1h",
              "lte": "now/h",
              "format": "epoch_millis"
            }
          }
        },
        {
          "match_phrase": {
            "modelId.keyword": {
              "query": "modelId01"
            }
          }
        }
      ]
    }
  }
}

结果为:

{
  "took" : 9,
  "timed_out" : false,
  "_shards" : {
    "total" : 140,
    "successful" : 140,
    "skipped" : 135,
    "failed" : 0
  },
  "hits" : {
    "total" : 0,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "aggregations" : {
    "modelId" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [ ]
    }
  }
}

在有模型调用的时候这个方法还好用,但是在无模型调用的时候这个返回结果就如上面的一样,是不包含任何信息的,错误次数的0和模型ID都没有了。 第二次设计因为在无模型调用的时候导致模型ID不能记录,然后也是不能实现指定m个模型的查询次数统计,也以失败告终。

第三次设计

经过两次失败的实际案例,我发现现有的知识已经不能满足需求了,我需要新的方法,我需要一个能给查询结果添加字段的方法,所以我去查询官方文档,让我找到了这个方法聚合元数据 也就是对聚合结果进行打标签。 我使用第一次的设计方案,然后添加上对聚合结果打标签的方法,就可以记录一次统计值的模型ID了。 查询语句如下:

{
  "aggs": {
    "error": {
      "filters": {
        "filters": {
          "error": {
            "query_string": {
              "query": "state:-1",
              "analyze_wildcard": true,
              "default_field": "*"
            }
          }
        }
      },
      "meta": {
        "modelId": "modelId01"
      }
    }
  },
  "size": 0,
  "query": {
    "bool": {
      "must": [
        {
          "bool": {
            "should": [
              {
                "match_phrase": {
                  "li": "D003" //说明这是一次模型调用
                }
              }
            ],
            "minimum_should_match": 1
          }
        },
        {
          "match_phrase": {
            "modelId..keyword": {
              "query": "modelId01"
            }
          }
        },
        {
          "range": {
            "x_st": {
              "gte": "now/h-1h-10s",
              "lte": "now/h-10s",
              "format": "epoch_millis"
            }
          }
        }
      ]
    }
  }
}

查询结果为:

{
  "took" : 88,
  "timed_out" : false,
  "_shards" : {
    "total" : 1095,
    "successful" : 1095,
    "skipped" : 1056,
    "failed" : 0
  },
  "hits" : {
    "total" : 0,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "aggregations" : {
    "error" : {
      "meta" : {
        "modelId" : "modelId01"
      },
      "buckets" : {
        "error" : {
          "doc_count" : 0
        }
      }
    }
  }
}

至此完成了统计需求。

总结

使用聚合元数据方法,可以对聚合的结果进行打标签,可以使用在聚合结果保存后再次进行terms聚合的时候使用,或者通过标签进行各种其他查询。

继续阅读 »

背景

在我们的项目中需要对聚合后的结果进行二次的terms的聚合。实际需求就是有n个模型,需要统计每个模型在每段时间的调用次数,然后需要查询指定m个模型的调用总次数。我们要为每个模型建立一个索引,然后为每个模型查一次这段时间内的使用次数。

注:我们记录的值只能从结果中拿取。

实现过程

第一次设计

每个模型在第一次设计的时候是两个字段,【调用次数】、【错误次数】,使用以下语句:

{
  "aggs": {
    "error": {
      "filters": {
        "filters": {
          "error": {
            "query_string": {
              "query": "state:-1",
              "analyze_wildcard": true,
              "default_field": "*"
            }
          }
        }
      }
    }
  },
  "size": 0,
  "query": {
    "bool": {
      "must": [
        {
          "bool": {
            "should": [
              {
                "match_phrase": {
                  "li": "D003" //说明这是一次模型调用
                }
              }
            ],
            "minimum_should_match": 1
          }
        },
        {
          "match_phrase": {
            "modelId..keyword": {
              "query": "modelId01"
            }
          }
        },
        {
          "range": {
            "x_st": {
              "gte": "now/h-1h-10s",
              "lte": "now/h-10s",
              "format": "epoch_millis"
            }
          }
        }
      ]
    }
  }
}

结果为:

{
  "took" : 215,
  "timed_out" : false,
  "_shards" : {
    "total" : 1095,
    "successful" : 1095,
    "skipped" : 1053,
    "failed" : 0
  },
  "hits" : {
    "total" : 0,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "aggregations" : {
    "error" : {
      "buckets" : {
        "error" : {
          "doc_count" : 0
        }
      }
    }
  }
}

解析后保存:

{"@timestamp":"2019-09-23T12:23:23.333","count":0,"error":0}

这种情况可以统计每个模型在某段时间内的调用次数,使用索引名来区分每个model。但是在统计指定m个模型的时候就不行了,使用索引名来查询的时候由于是指定m个,前缀不能使用* 匹配,并且不能罗列所有m个索引来查询,就无法达到统计的效果。 第一次设计因为不能在结果中记录模型ID导致不能统计指定的m个模型的数量,以失败告终。

第二次设计

既然需要在统计结果中记录模型ID,那就使用terms聚合来进行操作,先使用模型ID过滤一下数据,然后使用聚合唯一的模型ID,这样就有了模型ID。查询语句如下:

{
  "aggs": {
    "modelId": {
      "terms": {
        "field": "modelId.keyword",
        "size": 5,
        "order": {
          "_count": "desc"
        }
      }
    }
  },
  "size": 0,
  "query": {
    "bool": {
      "must": [
        {
          "match_phrase": {
            "modelId.keyword": {
              "query": "modelId01"
            }
          }
        },
        {
          "range": {
            "x_st": {
              "gte": "now/h-1h",
              "lte": "now/h",
              "format": "epoch_millis"
            }
          }
        },
        {
          "match_phrase": {
            "modelId.keyword": {
              "query": "modelId01"
            }
          }
        }
      ]
    }
  }
}

结果为:

{
  "took" : 9,
  "timed_out" : false,
  "_shards" : {
    "total" : 140,
    "successful" : 140,
    "skipped" : 135,
    "failed" : 0
  },
  "hits" : {
    "total" : 0,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "aggregations" : {
    "modelId" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [ ]
    }
  }
}

在有模型调用的时候这个方法还好用,但是在无模型调用的时候这个返回结果就如上面的一样,是不包含任何信息的,错误次数的0和模型ID都没有了。 第二次设计因为在无模型调用的时候导致模型ID不能记录,然后也是不能实现指定m个模型的查询次数统计,也以失败告终。

第三次设计

经过两次失败的实际案例,我发现现有的知识已经不能满足需求了,我需要新的方法,我需要一个能给查询结果添加字段的方法,所以我去查询官方文档,让我找到了这个方法聚合元数据 也就是对聚合结果进行打标签。 我使用第一次的设计方案,然后添加上对聚合结果打标签的方法,就可以记录一次统计值的模型ID了。 查询语句如下:

{
  "aggs": {
    "error": {
      "filters": {
        "filters": {
          "error": {
            "query_string": {
              "query": "state:-1",
              "analyze_wildcard": true,
              "default_field": "*"
            }
          }
        }
      },
      "meta": {
        "modelId": "modelId01"
      }
    }
  },
  "size": 0,
  "query": {
    "bool": {
      "must": [
        {
          "bool": {
            "should": [
              {
                "match_phrase": {
                  "li": "D003" //说明这是一次模型调用
                }
              }
            ],
            "minimum_should_match": 1
          }
        },
        {
          "match_phrase": {
            "modelId..keyword": {
              "query": "modelId01"
            }
          }
        },
        {
          "range": {
            "x_st": {
              "gte": "now/h-1h-10s",
              "lte": "now/h-10s",
              "format": "epoch_millis"
            }
          }
        }
      ]
    }
  }
}

查询结果为:

{
  "took" : 88,
  "timed_out" : false,
  "_shards" : {
    "total" : 1095,
    "successful" : 1095,
    "skipped" : 1056,
    "failed" : 0
  },
  "hits" : {
    "total" : 0,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "aggregations" : {
    "error" : {
      "meta" : {
        "modelId" : "modelId01"
      },
      "buckets" : {
        "error" : {
          "doc_count" : 0
        }
      }
    }
  }
}

至此完成了统计需求。

总结

使用聚合元数据方法,可以对聚合的结果进行打标签,可以使用在聚合结果保存后再次进行terms聚合的时候使用,或者通过标签进行各种其他查询。

收起阅读 »

社区日报 第737期 (2019-09-23)

1、将使用elasticsearch的成本降低90-99%
http://t.cn/EKCScjC

2、Elasticsearch调优实践
http://t.cn/AincWu86

3、Elasticsearch解决问题之道——请亮出你的DSL!
http://t.cn/AincnvSQ

编辑:cyberdak
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup 
继续阅读 »
1、将使用elasticsearch的成本降低90-99%
http://t.cn/EKCScjC

2、Elasticsearch调优实践
http://t.cn/AincWu86

3、Elasticsearch解决问题之道——请亮出你的DSL!
http://t.cn/AincnvSQ

编辑:cyberdak
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup  收起阅读 »

社区日报 第736期 (2019-09-22)

1.在ElasticSearch使用Machine Learning。
http://tinyurl.com/y5rtu9ej
2.(自备梯子)使用Elasticsearch和Kibana分析Ethereum。
http://tinyurl.com/y6fapn4z
3.(自备梯子)你的隐私值多少钱?
http://tinyurl.com/y5lk24vz

编辑:至尊宝
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup
继续阅读 »
1.在ElasticSearch使用Machine Learning。
http://tinyurl.com/y5rtu9ej
2.(自备梯子)使用Elasticsearch和Kibana分析Ethereum。
http://tinyurl.com/y6fapn4z
3.(自备梯子)你的隐私值多少钱?
http://tinyurl.com/y5lk24vz

编辑:至尊宝
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup 收起阅读 »

Lucene doc_value的理解复盘

之前看过很多doc_Value相关的文章,也看过elasticsearch官方的描述,但是总是感觉对doc_value如何提升聚合排序性能这块说的很简单(也许是我个人理解力的问题),总是不能深刻理解没有doc_Value的话会牺牲多大性能,再加上每次研究一半就搁置了,所以一直没能很好理解这块知识点,今天来重点复盘下。  本文不是科普文,不一定是完全正确的,大家可以讨论。
 
首先从elasticsearch入手,我们建立一个索引结构如下:
{
"info": {
"mappings": {
"info": {
"_all": {
"enabled": false
},
"properties": {
"age": {
"type": "int"
},
"time": {
"type": "long"
}
}
}
}
}
}
我这里特地拿非字符串类型的值做举例,大家在用MySQL的时候大多是用值精准匹配等条件,没有涉及到分词和多值,所以一开始很多用分词举例的时候我就糊涂了,这里我用数字举例说明下。
 
假设我们的需求是查询time=10的各个age包含的info有多少。这是一个搜索兼聚合的需求,首先要搜出来time:[1 , 10]的结果,然后在这些doc结果里统计,他们的age各自分别占了多少个doc。语句如下:
{
"query": {
"term": {
"time": 10
}
},
"aggs": {
"age_terms": {
"terms": {
"field": "age"
}
}
}
}

假设我们的数据是这样的:
docId        time           age
1               10               20
2              8                 21
3              9                 24
4              2                 23
5              10                22
6              10                22
 
 
结果也很明显了,返回doc为1,5,6的内容,聚合结果, age=20的doc_count=1,  age=22的doc_coutn=2。
 
demo介绍完了,说下假设没有doc_value,只有倒排索引我们要怎么实现这个效果。
 
首先搜索不用说了,走time字段的倒排索引,下表:
2:4
8:2
9:3
10:1,5,6
一目了然,一下就能把post_list结果拿到。
 
那么聚合是在1,5,6这个结果之上做的,因为聚合字段和排序字段不一样,time倒排索引中不包含age的信息,所以要想对age做聚合,就需要做类似回表的操作想办法取回每个doc对应的age值,然后在内存中遍历下算出来每个age对应的doc有几个(当然这个例子最多只有3个doc_count, 返回值只有3个doc)。
 
取回的方式,可以走age的倒排索引,遍历age索引的term_dictionary(不了解的同学可以理解为这就是一个排序的term列表),遍历要做的事情是什么呢:取出每个term后面的postling_list,看下list中有没有对应我搜索结果的doc_id,有的话记录下有几个,给这个term做下标记记录term的doc_count。 这个过程就比较狗了,假设term非常多,遍历一次的代价就非常高,所以在没有doc_value的情况下,遍历倒排索引就显得很差劲,倒排索引的价值本来就是避免数据遍历提升搜索性能,到了这种聚合需求上反而要用我做这么高代价的事儿,所以才需要一个出路避免这个问题。
 
这时候有人会说了,一个info对应一个age,那么当我遍历的时候,记录下这个doc有没有遍历过,当所有doc_id都遍历过一遍后就不遍历了,能提升一些性能吧。  首先如果运气不好,碰上你的doc要聚合的term出现在term_dictionary最后一个的时候,时间开销还是最坏情况的,其次,我这里用的是单个数值,如果一个field是多值的呢,换句话说,如果是分词的字符串呢,多值和分词其实一样,这种情况下当你遍历到一个term包含结果的某个doc_id时你不能说这个doc不会再后续的其他term中出现了,你还是要继续遍历完,所以为了满足这个需求,遍历全部term_dictionary是没跑的。
 
排序其实也差不多的,如果你要根据非搜索结果进行排序,一样要取出结果doc,对应排序字段的值,然后内存排序,所以内存排序聚合我觉得不是开销大的点,开销大的地方在于遍历倒排索引
 
其实讲到这里我的疑惑基本就解决了。接下来再说下doc_value
 
doc_value通俗的讲就是正排索引(这个词儿基本上所有文章都会这么说,说的也对,就是看多了有点想吐。。),其实正排索引就是我上面列举出来的那个值列表,只不过是一个字段一个doc_value,跟倒排索引一样,不是放在一起的(这点区别mysql聚集索引的叶子节点,聚集索引叶子节点是保存了全部的值,用主键绑定的,这里也说明了Lucene是索引和数据分离的,而MySQL是索引即数据,我是这么理解)。
time的doc_value

docId        time           
1               10              
2              8                
3              9                 
4              2                 
5              10               
6              10                
 
age的doc_value

docId        age
1               20
2               21
3               24
4               23
5               22
6               22
 
现在我们有了这样的一个结构可就厉害了,回到刚才的场景,搜索完结果是1,5,6,如果想按age进行聚合或者排序,那么只需要我们来到doc_value中,根据我们的id列表和doc_value的列表做交集拿出来结果对应的age就可以了,然后内存排序一下,实际上doc_value完全可以按照value先排好序,然后我们交集的结果就是排序结果了,都不用内存再排一次(暂时还不知道doc_value是不是根据value排过序)。
 
 
最后再说下我觉得其实可以优化的地方,之前我在问答也提问过,就是当搜索和排序/聚合使用相同字段的时候,还要不要走doc_value的问题。
 
因为如果是同一个字段那么完全没必要回表了,倒排索引本来就是field有序的所以排序问题解决。
 
其次聚合,刚才的例子中是单值的,如果是多值的话也不要紧,因为我们都知道查询条件的值了,单值的话 doc_count就等于total,多值的话 doc_count就等于其posting_list的length,多简单,省的走一次doc_value的操作。
 
不过那个问答回答的人太少,回答我的人的答复也蛮精彩的但是我仍然觉得这个操作是可以分开的。
 
求各路大神们对本文的观点做出指点和评论,或者我理解不对的地方提出指正。 对于想了解doc_value的同学希望这篇文章能解决你们的疑惑。
 
 
 
 
 
 
 
 
 
 
 
 
继续阅读 »
之前看过很多doc_Value相关的文章,也看过elasticsearch官方的描述,但是总是感觉对doc_value如何提升聚合排序性能这块说的很简单(也许是我个人理解力的问题),总是不能深刻理解没有doc_Value的话会牺牲多大性能,再加上每次研究一半就搁置了,所以一直没能很好理解这块知识点,今天来重点复盘下。  本文不是科普文,不一定是完全正确的,大家可以讨论。
 
首先从elasticsearch入手,我们建立一个索引结构如下:
{
"info": {
"mappings": {
"info": {
"_all": {
"enabled": false
},
"properties": {
"age": {
"type": "int"
},
"time": {
"type": "long"
}
}
}
}
}
}
我这里特地拿非字符串类型的值做举例,大家在用MySQL的时候大多是用值精准匹配等条件,没有涉及到分词和多值,所以一开始很多用分词举例的时候我就糊涂了,这里我用数字举例说明下。
 
假设我们的需求是查询time=10的各个age包含的info有多少。这是一个搜索兼聚合的需求,首先要搜出来time:[1 , 10]的结果,然后在这些doc结果里统计,他们的age各自分别占了多少个doc。语句如下:
{
"query": {
"term": {
"time": 10
}
},
"aggs": {
"age_terms": {
"terms": {
"field": "age"
}
}
}
}

假设我们的数据是这样的:
docId        time           age
1               10               20
2              8                 21
3              9                 24
4              2                 23
5              10                22
6              10                22
 
 
结果也很明显了,返回doc为1,5,6的内容,聚合结果, age=20的doc_count=1,  age=22的doc_coutn=2。
 
demo介绍完了,说下假设没有doc_value,只有倒排索引我们要怎么实现这个效果。
 
首先搜索不用说了,走time字段的倒排索引,下表:
2:4
8:2
9:3
10:1,5,6
一目了然,一下就能把post_list结果拿到。
 
那么聚合是在1,5,6这个结果之上做的,因为聚合字段和排序字段不一样,time倒排索引中不包含age的信息,所以要想对age做聚合,就需要做类似回表的操作想办法取回每个doc对应的age值,然后在内存中遍历下算出来每个age对应的doc有几个(当然这个例子最多只有3个doc_count, 返回值只有3个doc)。
 
取回的方式,可以走age的倒排索引,遍历age索引的term_dictionary(不了解的同学可以理解为这就是一个排序的term列表),遍历要做的事情是什么呢:取出每个term后面的postling_list,看下list中有没有对应我搜索结果的doc_id,有的话记录下有几个,给这个term做下标记记录term的doc_count。 这个过程就比较狗了,假设term非常多,遍历一次的代价就非常高,所以在没有doc_value的情况下,遍历倒排索引就显得很差劲,倒排索引的价值本来就是避免数据遍历提升搜索性能,到了这种聚合需求上反而要用我做这么高代价的事儿,所以才需要一个出路避免这个问题。
 
这时候有人会说了,一个info对应一个age,那么当我遍历的时候,记录下这个doc有没有遍历过,当所有doc_id都遍历过一遍后就不遍历了,能提升一些性能吧。  首先如果运气不好,碰上你的doc要聚合的term出现在term_dictionary最后一个的时候,时间开销还是最坏情况的,其次,我这里用的是单个数值,如果一个field是多值的呢,换句话说,如果是分词的字符串呢,多值和分词其实一样,这种情况下当你遍历到一个term包含结果的某个doc_id时你不能说这个doc不会再后续的其他term中出现了,你还是要继续遍历完,所以为了满足这个需求,遍历全部term_dictionary是没跑的。
 
排序其实也差不多的,如果你要根据非搜索结果进行排序,一样要取出结果doc,对应排序字段的值,然后内存排序,所以内存排序聚合我觉得不是开销大的点,开销大的地方在于遍历倒排索引
 
其实讲到这里我的疑惑基本就解决了。接下来再说下doc_value
 
doc_value通俗的讲就是正排索引(这个词儿基本上所有文章都会这么说,说的也对,就是看多了有点想吐。。),其实正排索引就是我上面列举出来的那个值列表,只不过是一个字段一个doc_value,跟倒排索引一样,不是放在一起的(这点区别mysql聚集索引的叶子节点,聚集索引叶子节点是保存了全部的值,用主键绑定的,这里也说明了Lucene是索引和数据分离的,而MySQL是索引即数据,我是这么理解)。
time的doc_value

docId        time           
1               10              
2              8                
3              9                 
4              2                 
5              10               
6              10                
 
age的doc_value

docId        age
1               20
2               21
3               24
4               23
5               22
6               22
 
现在我们有了这样的一个结构可就厉害了,回到刚才的场景,搜索完结果是1,5,6,如果想按age进行聚合或者排序,那么只需要我们来到doc_value中,根据我们的id列表和doc_value的列表做交集拿出来结果对应的age就可以了,然后内存排序一下,实际上doc_value完全可以按照value先排好序,然后我们交集的结果就是排序结果了,都不用内存再排一次(暂时还不知道doc_value是不是根据value排过序)。
 
 
最后再说下我觉得其实可以优化的地方,之前我在问答也提问过,就是当搜索和排序/聚合使用相同字段的时候,还要不要走doc_value的问题。
 
因为如果是同一个字段那么完全没必要回表了,倒排索引本来就是field有序的所以排序问题解决。
 
其次聚合,刚才的例子中是单值的,如果是多值的话也不要紧,因为我们都知道查询条件的值了,单值的话 doc_count就等于total,多值的话 doc_count就等于其posting_list的length,多简单,省的走一次doc_value的操作。
 
不过那个问答回答的人太少,回答我的人的答复也蛮精彩的但是我仍然觉得这个操作是可以分开的。
 
求各路大神们对本文的观点做出指点和评论,或者我理解不对的地方提出指正。 对于想了解doc_value的同学希望这篇文章能解决你们的疑惑。
 
 
 
 
 
 
 
 
 
 
 
  收起阅读 »

Elastic日报 第735期 (2019-09-21)

1.es字符串包含查询的几种方案

http://t.cn/AinyGFZD

2.es6.2版本利用脚本查询为空数据的方法

http://t.cn/AinyqBJN

3.es中 “先filter后aggs” 和 “在aggs执行filter” 的区别

http://t.cn/AinyfBkq

继续阅读 »

1.es字符串包含查询的几种方案

http://t.cn/AinyGFZD

2.es6.2版本利用脚本查询为空数据的方法

http://t.cn/AinyqBJN

3.es中 “先filter后aggs” 和 “在aggs执行filter” 的区别

http://t.cn/AinyfBkq

收起阅读 »

社区日报 第734期 (2019-09-20)

1、开源:基于React的Elasticsearch UI组件库
https://tinyurl.com/y4js6mf7
2、如何将edis缓存层添加到Elasticsearch查询?(梯子)
https://tinyurl.com/yyg5wue3
3、基于vector字段的文本相似度搜索
https://tinyurl.com/y3k2kfsd

编辑:铭毅天下
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup 
继续阅读 »
1、开源:基于React的Elasticsearch UI组件库
https://tinyurl.com/y4js6mf7
2、如何将edis缓存层添加到Elasticsearch查询?(梯子)
https://tinyurl.com/yyg5wue3
3、基于vector字段的文本相似度搜索
https://tinyurl.com/y3k2kfsd

编辑:铭毅天下
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup  收起阅读 »

社区日报 第733期 (2019-09-19)

1、ES时间序列的聚合与查询
http://tinyurl.com/yxvtl866
2、k8s日志收集指南
http://tinyurl.com/yyv373ss
3、elastic stack的告警
http://tinyurl.com/y4cnmdo3
 
编辑:wt
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup 
继续阅读 »
1、ES时间序列的聚合与查询
http://tinyurl.com/yxvtl866
2、k8s日志收集指南
http://tinyurl.com/yyv373ss
3、elastic stack的告警
http://tinyurl.com/y4cnmdo3
 
编辑:wt
归档:https://ela.st/cn-daily-all
订阅:https://ela.st/cn-daily-sub
沙龙:https://ela.st/cn-meetup  收起阅读 »

关于sum bucket 与Filter Aggregation 结合的写法分享

我们可以用ES的桶来实现这样的需求,找出汽车厂商每个颜色的车辆数量
当如果需求是,找出汽车厂商里的车一共有多少种颜色呢?
 我们可以使用sum bucket ,默认情况下,可以参考官方文档
https://www.elastic.co/guide/e ... ml%23
 
但如果我们想找到售价大于100W的车,有多少种颜色呢?
这就需要Filter Aggregation   和 上文的sum bucket结合
 
这里有个需要注意的地方,sum_bucket的位置不要跟 Filter Aggregation 同级,而是应该在其下一级:
    "query": {
"query": {
"bool": {
"filter": {
"bool": {
"must": [
{
"term": {
"delflag": 0
}
},
{
"term": {
"is_child": 1
}
}
],
"must_not":
}
}
}
},
"aggs": {
"valid_sales_people": {
"filter": {
"bool": {
"must_not": {
"terms": {
"status": [
0,
1,
7
]
}
}
}
},
"aggs": {
"render_people": {
"terms": {
"field": "uid",
"size": 2147483647
},
"aggs": {
"unique_people": {
"cardinality": {
"field": "uid"
}
}
}
},
"member_count": {
"sum_bucket": {
"buckets_path": "render_people>unique_people"
}
}
}
}
}
},
如代码所示,我希望对status not in (0,1,7)的uid(用户)进行聚合,并想得到uid桶种类的求和,那么member_count就应该与render_people同级,而不是把member_count放到和与valid_sales_people同一级。
 
如果将member_count 与valid_sales_people放到同一级,会报一个错:sum_bucket的第一个聚合必须是多桶聚合。究其原因,应该是加上filter aggregation后,valid_sales_people已不具有多桶聚合属性(因为附带了filter过滤条件),而其下的render_people则具有了多桶聚合属性。所以member_count应该与render_people放在同级,对应的buckets_path也自然改为render_people>unique_people
 

 
继续阅读 »
我们可以用ES的桶来实现这样的需求,找出汽车厂商每个颜色的车辆数量
当如果需求是,找出汽车厂商里的车一共有多少种颜色呢?
 我们可以使用sum bucket ,默认情况下,可以参考官方文档
https://www.elastic.co/guide/e ... ml%23
 
但如果我们想找到售价大于100W的车,有多少种颜色呢?
这就需要Filter Aggregation   和 上文的sum bucket结合
 
这里有个需要注意的地方,sum_bucket的位置不要跟 Filter Aggregation 同级,而是应该在其下一级:
    "query": {
"query": {
"bool": {
"filter": {
"bool": {
"must": [
{
"term": {
"delflag": 0
}
},
{
"term": {
"is_child": 1
}
}
],
"must_not":
}
}
}
},
"aggs": {
"valid_sales_people": {
"filter": {
"bool": {
"must_not": {
"terms": {
"status": [
0,
1,
7
]
}
}
}
},
"aggs": {
"render_people": {
"terms": {
"field": "uid",
"size": 2147483647
},
"aggs": {
"unique_people": {
"cardinality": {
"field": "uid"
}
}
}
},
"member_count": {
"sum_bucket": {
"buckets_path": "render_people>unique_people"
}
}
}
}
}
},
如代码所示,我希望对status not in (0,1,7)的uid(用户)进行聚合,并想得到uid桶种类的求和,那么member_count就应该与render_people同级,而不是把member_count放到和与valid_sales_people同一级。
 
如果将member_count 与valid_sales_people放到同一级,会报一个错:sum_bucket的第一个聚合必须是多桶聚合。究其原因,应该是加上filter aggregation后,valid_sales_people已不具有多桶聚合属性(因为附带了filter过滤条件),而其下的render_people则具有了多桶聚合属性。所以member_count应该与render_people放在同级,对应的buckets_path也自然改为render_people>unique_people
 

  收起阅读 »