ES中的MR

elastic search真是個讓人既愛又恨的東西,性能強勁,功能強大,但就是在使用中遇到種種問題(多半因為文檔太差)。
文章記錄一下在es 2.2.0版本中使用Scripted Metric Aggregation(也就是牛X的map-reduce)的方法。
api這是官方文檔,但是并不詳細,看完并不能干出什么事來.這是java api

下面貼出完整的實踐內容和代碼(敏感內容已抹去),目的是根據行為日志得出活躍分值

  • 在elasticsearch.yml文件中添加配置啟用groovy腳本
script.engine.groovy.file.aggs: true
script.engine.groovy.file.mapping: true
script.engine.groovy.file.search: true
script.engine.groovy.file.update: true
script.engine.groovy.file.plugin: true
script.engine.groovy.indexed.aggs: true
script.engine.groovy.indexed.mapping: false
script.engine.groovy.indexed.search: true
script.engine.groovy.indexed.update: false
script.engine.groovy.indexed.plugin: false
script.engine.groovy.inline.aggs: true
script.engine.groovy.inline.mapping: true
script.engine.groovy.inline.search: true
script.engine.groovy.inline.update: true
script.engine.groovy.inline.plugin: true
  • 這是es 中保存的數據
curl -XPUT "http://10.1.200.34:9200/behavior-2017.02/candidate/AVoG9St-6pLzqkumYcIr" -d '
{
    "businessLine": "platform",
    "createTime": "2017-02-04T02:30:14.000Z",
    "latitude": 0,
    "longitude": 0,
    "name": "c_login",
    "network": "unknown",
    "ownerId": 6403128,
    "ownerType": "candidate",
    "params": {
      "positionId": "2112620"
    },
    "uuid": "a36556ed286348aeb970e0ba1cda1447"
}'
curl -XPUT "http://10.1.200.34:9200/behavior-2017.02/candidate/AVoG9SgJP_y-H6mvM9g8" -d '
{
    "businessLine": "platform",
    "clientIp": "*3.1*8.113.*6",
    "createTime": "2017-02-04T02:30:13.683Z",
    "latitude": 0,
    "longitude": 0,
    "name": "c_login",
    "network": "unknown",
    "ownerId": 6403118,
    "ownerType": "candidate",
    "terminal": "pc",
    "userAgent": "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36",
    "uuid": "0d9b007e3d624180aefd57e7df0b656c",
}'
curl -XPUT "http://10.1.200.34:9200/behavior-2017.02/candidate/AVoG9SgJP_y-H6mvM9g1" -d '
{
    "businessLine": "platform",
    "clientIp": "*23.*8.*3.1*",
    "createTime": "2017-02-04T02:30:13.683Z",
    "latitude": 0,
    "longitude": 0,
    "name": "c_register",
    "network": "unknown",
    "ownerId": 6403127,
    "ownerType": "candidate",
    "terminal": "pc",
    "userAgent": "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36",
    "uuid": "0d9b007e3d624180aefd57e7df0b656c",
}'
  • 這是查詢用的腳本,以id為分組,統計行為信息。
curl -XGET "http://10.1.200.34:9200/behavior*/_search/?pretty" -d '
{
  "aggs": {
    "group_by_ownerId" : { 
        "terms" : {
         "field" : "ownerId" 
         },
         "aggs":{
          "livenessScore": {
            "scripted_metric": {
                "init_script" : {"file": "user-liveness-score-init"},
                "map_script" : {"file": "user-liveness-score-map"},
                "combine_script" : {"file": "user-liveness-score-combine"},
                "reduce_script" : {"file": "user-liveness-score-reduce"},
                "params": {
                    "_agg": {"resumeScore":{6403127:60}}
                }
            }
        }
         } 
      }
  },
  "query": {
    "filtered": {
      "query": {
        "match_all": {}
      }
    }
  },
  "fields": [
    "ownerId"
  ]
}'
  • 腳本及腳本的存放位置
[root@jiqi001 scripts]# pwd
/apps/elasticsearch/config/scripts
[root@jiqi001 scripts]# ls
user-liveness-score-combine.groovy  user-liveness-score-init.groovy  user-liveness-score-map.groovy  user-liveness-score-reduce.groovy
_agg.loginScoreInWeek=0;
_agg.loginScoreInMonth=0;
_agg.registerScoreInWeek=0;
_agg.registerScoreInMonth=0;
~                      
"user-liveness-score-init.groovy" 15L, 383C
xDaysBefore = Math.round((new Date().getTime() - doc.createTime) / 1000 / 60 / 60 / 24);
behaviorName = doc.name.value;
resumeScore = _agg.resumeScore.get(String.valueOf(doc.ownerId.value));
if (behaviorName.equals("c_login")) {
    if (xDaysBefore <= 7) {
        if (_agg.loginScoreInWeek < 4) {
            _agg.loginScoreInWeek += 2;
        }
    } else if (7 < xDaysBefore && xDaysBefore <= 30) {
        if (_agg.loginScoreInMonth < 2) {
            _agg.loginScoreInMonth += 1;
        }
    }
}  else if (behaviorName.equals("c_register")) {
    if (resumeScore != null && resumeScore > 30) {
        if (xDaysBefore <= 7) {
            if (_agg.registerScoreInWeek == 0) {
                _agg.registerScoreInWeek = 5;
            }
        } else if (7 < xDaysBefore && xDaysBefore <= 30) {
            if (_agg.registerScoreInMonth == 0) {
                _agg.registerScoreInMonth = 3;
            }
        }
    }
};
~                                                                                                                                                                                                                                       
"user-liveness-score-map.groovy" 66L, 2657C
```
```shell
_agg
~                                                                                                             
"user-liveness-score-combine.groovy" 1L, 5C
```
````shell
double score = 0;
loginScoreInWeek=0;
loginScoreInMonth=0;
registerScoreInWeek=0;
registerScoreInMonth=0;
for (a in _aggs) {
  if(loginScoreInWeek<4){
    loginScoreInWeek += a.get("loginScoreInWeek");
  };
  if(loginScoreInMonth<2){
    loginScoreInMonth += a.get("loginScoreInMonth");
  };
  if(registerScoreInWeek<5){
    registerScoreInWeek += a.get("registerScoreInWeek");
  };
  if(registerScoreInMonth<3){
    registerScoreInMonth += a.get("registerScoreInMonth");
  };
 };
  if(loginScoreInWeek>4){
    loginScoreInWeek =4;
  };
  if(loginScoreInMonth>2){
    loginScoreInMonth =2;
  };
  if(registerScoreInWeek>5){
    registerScoreInWeek =5;
  };
  if(registerScoreInMonth>3){
    registerScoreInMonth =3;
  };
 score += loginScoreInWeek;
 score += loginScoreInMonth;
 score += registerScoreInWeek;
 score += registerScoreInMonth;
 return score;
"user-liveness-score-reduce.groovy"
```

- Java代碼
```java
    private Map<String, Double> getUsersLiveScore(Map<String, Object> userAndResumeScore) throws InterruptedException, ExecutionException {
        Map<String, Double> userAndLivenessScore = new HashMap<>();
        Map<String, Object> param = new HashMap<>();
        param.put("resumeScore", userAndResumeScore);
        Map<String, Object> params = new HashMap<>();
        params.put("_agg", param);
        Client client = eSClient.getClient();
        AggregationBuilder aggregation = AggregationBuilders.terms("group_by_ownerId")
                .field("ownerId")
                .subAggregation(
                        AggregationBuilders.scriptedMetric("livenessScore")
                                .params(params)
                                .initScript(new Script("user-liveness-score-init", ScriptService.ScriptType.FILE, "groovy", null))
                                .mapScript(new Script("user-liveness-score-map", ScriptService.ScriptType.FILE, "groovy", null))
                                .combineScript(new Script("user-liveness-score-combine", ScriptService.ScriptType.FILE, "groovy", null))
                                .reduceScript(new Script("user-liveness-score-reduce", ScriptService.ScriptType.FILE, "groovy", null))
                );
        TermsQueryBuilder ownerId = QueryBuilders.termsQuery("ownerId", userAndResumeScore.keySet());
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        boolQueryBuilder.must(ownerId);
        boolQueryBuilder.must(QueryBuilders.rangeQuery("createTime").gte(DateTime.now().plusDays(-30).toDate()));
        SearchResponse response = client.prepareSearch("behavior-*")
                .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                .setQuery(boolQueryBuilder)
                .addAggregation(aggregation)
                .setFrom(0)
                .setSize(3000)
                .addField("ownerId")
                .execute()
                .get();
        for (Aggregation agg : response.getAggregations()) {
            List<Terms.Bucket> buckets = ((LongTerms) agg).getBuckets();
            for (Terms.Bucket bucket : buckets) {
                String userId = bucket.getKeyAsString();
                for (Aggregation agg2 : bucket.getAggregations()) {
                    double score = (double) ((InternalScriptedMetric) agg2).aggregation();
                    userAndLivenessScore.put(String.valueOf(userId), score);
                }
            }
        }
        return userAndLivenessScore;
    }
```
- Tips
1.參數param必須放在_agg變量里。
2.可以用"combine_script":"_agg;","reduce_script":"_aggs;"來調試腳本。
3.combine組合的結果會以分片為分組,并非整個查詢結果的組合.比如查詢一個index如果在5個分片上有結果則返回一個長度為5的數組,
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,520評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,362評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,805評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,541評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,896評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,887評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,062評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,608評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,356評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,555評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,077評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,769評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,175評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,489評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,289評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,516評論 2 379

推薦閱讀更多精彩內容