ElasticSearch初探

      最近在做数据漏斗的需求,就是统计ADX调用到我们DSP系统,我们DSP系统内部,对流量的过滤情况,做一个可视化界面,供PM查看。因为存储采用的ES,之前没有在项目中使用过,这两天看官方文档恶补了下,说实话,英文的官方文档真的是最好的学习资料,写语句时遇到了问题,去论坛发帖,一个外国友人回复了,因为我在提问时没有把代码格式化,以至于可读性非常差,后来改了,可读性增强,这样对别人也是一种尊重,别人浏览到这个帖子后,也能很清晰地看懂。很喜欢这种感觉,以后以官方文档为资料,不过英语真的是硬伤,需要多学习。外国友人给的建议

需求:统计参与竞价的PV数,条件是开始时间和结束时间,adxid,adlist不能为空。指标是对sidcount求和。其中对我来说难点在adlist不能为空这个条件。

下面我们看一下索引的mapping

{
  "lm_dsp_data_search_funnel-2018.08.10": {
    "mappings": {
      "doc": {
        "properties": {
          "@timestamp": {
            "type": "date"
          },
          "@version": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "abtest": {
            "type": "keyword"
          },
          "adlist": {
            "type": "nested",
            "properties": {
              "promotionid": {
                "type": "integer"
              },
              "sn": {
                "type": "integer"
              }
            }
          },
          "adxid": {
            "type": "keyword"
          },
          "age": {
            "type": "integer"
          },
          "deviceidmd5": {
            "type": "keyword"
          },
          "displocal1": {
            "type": "integer"
          },
          "displocal2": {
            "type": "integer"
          },
          "escount": {
            "type": "long"
          },
          "gender": {
            "type": "integer"
          },
          "interest": {
            "type": "integer"
          },
          "mediaid": {
            "type": "integer"
          },
          "os": {
            "type": "integer"
          },
          "sid": {
            "type": "keyword"
          },
          "sidcount": {
            "type": "integer"
          },
          "slotid": {
            "type": "integer"
          },
          "stime": {
            "type": "long"
          },
          "styleids": {
            "type": "integer"
          },
          "tags": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "userip": {
            "type": "keyword"
          }
        }
      }
    }
  }
}

可以发现 adlist 采用了 nested 的方式

查询全部时,返回数据的一个结构,如下图所示:

 

 

 

 

 

 

 

最开始想使用es的script实现,写了下面的语句:

GET lm_dsp_data_search_funnel-2018.08.10/_search
{
  "size": 10, 
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "adxid": "u-2cbc34ryk3v43nkdq9g"
          }
        },
        {
          "range": {
            "stime": {
              "gte": 1533859200000,
              "lte": 1533873600000
            }
          }
        }
      ],
      "filter": {
        "script": {
        "script": "doc['adlist'].values.length > 0"
          }
      }
    }
  }, 
  "aggs": {
    "sn_count": {
      "sum": {
        "field": "sidcount"
      }
    }
  }
}

上面的语句报下面的错误:

{
  "error": {
    "root_cause": [
      {
        "type": "script_exception",
        "reason": "runtime error",
        "script_stack": [
          "org.elasticsearch.search.lookup.LeafDocLookup.get(LeafDocLookup.java:81)",
          "org.elasticsearch.search.lookup.LeafDocLookup.get(LeafDocLookup.java:39)",
          "doc['adlist'].values.length > 0",
          "    ^---- HERE"
        ],
        "script": "doc['adlist'].values.length > 0",
        "lang": "painless"
      }
    ],
    "type": "search_phase_execution_exception",
    "reason": "all shards failed",
    "phase": "query",
    "grouped": true,
    "failed_shards": [
      {
        "shard": 0,
        "index": "lm_dsp_data_search_funnel-2018.08.10",
        "node": "eMpHZINKRxeM1YsKNDcjng",
        "reason": {
          "type": "script_exception",
          "reason": "runtime error",
          "script_stack": [
            "org.elasticsearch.search.lookup.LeafDocLookup.get(LeafDocLookup.java:81)",
            "org.elasticsearch.search.lookup.LeafDocLookup.get(LeafDocLookup.java:39)",
            "doc['adlist'].values.length > 0",
            "    ^---- HERE"
          ],
          "script": "doc['adlist'].values.length > 0",
          "lang": "painless",
          "caused_by": {
            "type": "illegal_argument_exception",
            "reason": "No field found for [adlist] in mapping with types []"
          }
        }
      }
    ]
  },
  "status": 500
}

从网上查资料,也没有解决,写脚本这个技能后面需要再学习一下。后来转换了想法,用别的方式实现。

方法一:

GET lm_dsp_data_search_funnel-2018.08.10/_search
{
  "size": 0,
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "adxid": {
              "value": "u-2cbc34ryk3v43nkdq9g"
            }
          }
        },
        {
          "range": {
            "stime": {
              "gte": 1533859200000,
              "lte": 1533898800000
            }
          }
        },
        {
          "nested" : {
            "path" : "adlist",
            "score_mode" : "none",
            "query" : {
              "exists":{"field":"adlist"}
            }
          }
        }
      ]
    }
  },
  "aggs": {
    "count": {
      "sum": {
        "field": "sidcount"
      }
    }
  }
}

上面的会过滤掉{"adlist":[]}这样的数据,当拿不准的时候,看官方文档:

 

 

方式二:

GET lm_dsp_data_search_funnel-2018.08.10/_search
{
  "size": 0,
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "adxid": {
              "value": "u-2cbc34ryk3v43nkdq9g"
            }
          }
        },
        {
          "range": {
            "stime": {
              "from": 1533891139904,
              "to": null,
              "include_lower": false,
              "include_upper": false,
              "boost": 1
            }
          }
        },
        {
          "nested" : {
            "path" : "adlist",
            "score_mode" : "none",
            "query" : {
                "bool" : {
                    "must" : [
                      { "range" : {"adlist.promotionid" : {"gte" : "0"}} }
                    ]
                }
            }
          }
        }
      ]
    }
  },
  "aggs": {
    "count": {
      "sum": {
        "field": "sidcount"
      }
    }
  }
}

上面的两种方法都能实现需求:

{
  "took": 42,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 397105,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "count": {
      "value": 397105
    }
  }
}

这个需求的时间花在了梳理需求,日志埋点,把日志收集到es中,统计数据,还有就是熟悉es的查询语句,今天是周五,下周一是开始的最后一天,需要快速把语句融入到代码中,这只是其中一个20分之一的需求,任务重大,不过当梳理清楚需求后,知道怎么做,下面的工作就会轻松些,很喜欢这种在工作中学习的感觉。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Java8新特性及实战视频教程完整版Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。 Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用Lambda 表达式可以使代码变的更加简洁紧凑。Java8实战视频-01让方法参数具备行为能力Java8实战视频-02Lambda表达式初探Java8实战视频-03Lambda语法精讲Java8实战视频-04Lambda使用深入解析Java8实战视频-05Lambda方法推导详细解析-上.wmvJava8实战视频-06Lambda方法推导详细解析-下Java8实战视频-07Stream入门及Stream在JVM中的线程表现Java8实战视频-08Stream知识点总结Stream源码阅读Java8实战视频-09如何创建Stream上集Java8实战视频-10如何创建Stream下集.wmvJava8实战视频-11Stream之filter,distinct,skip,limit,map,flatmap详细介绍Java8实战视频-12Stream之Find,Match,Reduce详细介绍Java8实战视频-13NumericStream的详细介绍以及和Stream之间的相互转换Java8实战视频-14Stream综合练习,熟练掌握API的用法Java8实战视频-15在Optional出现之前经常遇到的空指针异常.wmvJava8实战视频-16Optional的介绍以及API的详解Java8实战视频-17Optional之flatMap,综合练习,Optional源码剖析Java8实战视频-18初识Collector体会Collector的强大Java8实战视频-19Collector使用方法深入详细介绍-01Java8实战视频-20Collector使用方法深入详细介绍-02Java8实战视频-21Collector使用方法深入详细介绍-03.wmvJava8实战视频-22Collector使用方法深入详细介绍-04Java8实战视频-23Collector原理讲解,JDK自带Collector源码深度剖析Java8实战视频-24自定义Collector,结合Stream的使用详细介绍Java8实战视频-25Parallel Stream编程体验,充分利用多核机器加快计算速度Java8实战视频-26Fork Join框架实例深入讲解Java8实战视频-27Spliterator接口源码剖析以及自定义Spliterator实现一个Stream.wmvJava8实战视频-28Default方法的介绍和简单的例子Java8实战视频-29Default方法解决多重继承冲突的三大原则详细介绍Java8实战视频-30多线程Future设计模式原理详细介绍,并且实现一个Future程序Java8实战视频-31JDK自带Future,Callable,ExecutorService介绍Java8实战视频-32实现一个异步基于事件回调的Future程序.wmvJava8实战视频-33CompletableFuture用法入门介绍Java8实战视频-34CompletableFuture之supplyAsync详细介绍Java8实战视频-35CompletableFuture流水线工作,join多个异步任务详细讲解Java8实战视频-36CompletableFuture常用API的重点详解-上Java8实战视频-37CompletableFuture常用API的重点详解-下Java8实战视频-38JDK老DateAPI存在的问题,新的DateAPI之LocalDate用法及其介绍.wmvJava8实战视频-39New Date API之LocalTime,LocalDateTime,Instant,Duration,Period详细介绍Java8实战视频-40New Date API之format和parse介绍

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值