Elasticsearch 5.x 字段折叠的使用

199aon3omgg1vjpg.jpg

 在 Elasticsearch 5.x 有一个字段折叠(Field Collapsing,#22337)的功能非常有意思,在这里分享一下,
 
字段折叠是一个很有历史的需求了,可以看这个 issue,编号#256,最初是2010年7月提的issue,也是讨论最多的帖子之一(240+评论),熬了6年才支持的特性,你说牛不牛,哈哈。
 
目测该特性将于5.3发布,尝鲜地址:Elasticsearch-5.3.0-SNAPSHOT,文档地址:search-request-collapse
 
So,什么是字段折叠,可以理解就是按特定字段进行合并去重,比如我们有一个菜谱搜索,我希望按菜谱的“菜系”字段进行折叠,即返回结果每个菜系都返回一个结果,也就是按菜系去重,我搜索关键字“鱼”,要去返回的结果里面各种菜系都有,有湘菜,有粤菜,有中餐,有西餐,别全是湘菜,就是这个意思,通过按特定字段折叠之后,来丰富搜索结果的多样性。
 
说到这里,有人肯定会想到,使用 term agg+ top hits agg 来实现啊,这种组合两种聚和的方式可以实现上面的功能,不过也有一些局限性,比如,不能分页,#4915;结果不够精确(top term+top hits,es 的聚合实现选择了牺牲精度来提高速度);数据量大的情况下,聚合比较慢,影响搜索体验。
 
而新的的字段折叠的方式是怎么实现的的呢,有这些要点:
  1. 折叠+取 inner_hits 分两阶段执行(组合聚合的方式只有一个阶段),所以 top hits 永远是精确的。
  2. 字段折叠只在 top hits 层执行,不需要每次都在完整的结果集上对为每个折叠主键计算实际的 doc values 值,只对 top hits 这小部分数据操作就可以,和 term agg 相比要节省很多内存。
  3. 因为只在 top hits 上进行折叠,所以相比组合聚合的方式,速度要快很多。
  4. 折叠 top docs 不需要使用全局序列(global ordinals)来转换 string,相比 agg 这也节省了很多内存。
  5. 分页成为可能,和常规搜索一样,具有相同的局限,先获取 from+size 的内容,再合并。
  6. search_after 和 scroll 暂未实现,不过具备可行性。
  7.  折叠只影响搜索结果,不影响聚合,搜索结果的 total 是所有的命中纪录数,去重的结果数未知(无法计算)。

 
下面来看看具体的例子,就知道怎么回事了,使用起来很简单。
  • 先准备索引和数据,这里以菜谱为例,name:菜谱名,type 为菜系,rating 为用户的累积平均评分

DELETE recipes
PUT recipes
POST recipes/type/_mapping
{
"properties": {
"name":{
"type": "text"
},
"rating":{
"type": "float"
},"type":{
"type": "keyword"
}
}
}
POST recipes/type/
{
"name":"清蒸鱼头","rating":1,"type":"湘菜"
}

POST recipes/type/
{
"name":"剁椒鱼头","rating":2,"type":"湘菜"
}

POST recipes/type/
{
"name":"红烧鲫鱼","rating":3,"type":"湘菜"
}

POST recipes/type/
{
"name":"鲫鱼汤(辣)","rating":3,"type":"湘菜"
}

POST recipes/type/
{
"name":"鲫鱼汤(微辣)","rating":4,"type":"湘菜"
}

POST recipes/type/
{
"name":"鲫鱼汤(变态辣)","rating":5,"type":"湘菜"
}

POST recipes/type/
{
"name":"广式鲫鱼汤","rating":5,"type":"粤菜"
}

POST recipes/type/
{
"name":"鱼香肉丝","rating":2,"type":"川菜"
}

POST recipes/type/
{
"name":"奶油鲍鱼汤","rating":2,"type":"西菜"

  • 现在我们看看普通的查询效果是怎么样的,搜索关键字带“鱼”的菜,返回3条数据

POST recipes/type/_search
{
"query": {"match": {
"name": "鱼"
}},"size": 3
全是湘菜,我的天,最近上火不想吃辣,这个第一页的结果对我来说就是垃圾,如下:
{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 9,
    "max_score": 0.26742277,
    "hits": [
      {
        "_index": "recipes",
        "_type": "type",
        "_id": "AVoESHYF_OA-dG63Txsd",
        "_score": 0.26742277,
        "_source": {
          "name": "鲫鱼汤(变态辣)",
          "rating": 5,
          "type": "湘菜"
        }
      },
      {
        "_index": "recipes",
        "_type": "type",
        "_id": "AVoESHXO_OA-dG63Txsa",
        "_score": 0.19100356,
        "_source": {
          "name": "红烧鲫鱼",
          "rating": 3,
          "type": "湘菜"
        }
      },
      {
        "_index": "recipes",
        "_type": "type",
        "_id": "AVoESHWy_OA-dG63TxsZ",
        "_score": 0.19100356,
        "_source": {
          "name": "剁椒鱼头",
          "rating": 2,
          "type": "湘菜"
        }
      }
    ]
  }
}
我们再看看,这次我想加个评分排序,大家都喜欢的是那些,看看有没有喜欢吃的,执行查询:
POST recipes/type/_search
{
"query": {"match": {
"name": "鱼"
}},"sort": [
{
"rating": {
"order": "desc"
}
}
],"size": 3
结果稍微好点了,不过3个里面2个是湘菜,还是有点不合适,结果如下:
{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 9,
    "max_score": null,
    "hits": [
      {
        "_index": "recipes",
        "_type": "type",
        "_id": "AVoESHYF_OA-dG63Txsd",
        "_score": null,
        "_source": {
          "name": "鲫鱼汤(变态辣)",
          "rating": 5,
          "type": "湘菜"
        },
        "sort": [
          5
        ]
      },
      {
        "_index": "recipes",
        "_type": "type",
        "_id": "AVoESHYW_OA-dG63Txse",
        "_score": null,
        "_source": {
          "name": "广式鲫鱼汤",
          "rating": 5,
          "type": "粤菜"
        },
        "sort": [
          5
        ]
      },
      {
        "_index": "recipes",
        "_type": "type",
        "_id": "AVoESHX7_OA-dG63Txsc",
        "_score": null,
        "_source": {
          "name": "鲫鱼汤(微辣)",
          "rating": 4,
          "type": "湘菜"
        },
        "sort": [
          4
        ]
      }
    ]
  }
}
现在我知道了,我要看看其他菜系,这家不是还有西餐、广东菜等各种菜系的么,来来,帮我每个菜系来一个菜看看,换 terms agg 先得到唯一的 term 的 bucket,再组合 top_hits agg,返回按评分排序的第一个 top hits,有点复杂,没关系,看下面的查询就知道了:
GET recipes/type/_search
{
"query": {
"match": {
"name": "鱼"
}
},
"sort": [
{
"rating": {
"order": "desc"
}
}
],"aggs": {
"type": {
"terms": {
"field": "type",
"size": 10
},"aggs": {
"rated": {
"top_hits": {
"sort": [{
"rating": {"order": "desc"}
}],
"size": 1
}
}
}
}
},
"size": 0,
"from": 0
看下面的结果,虽然 json 结构有点复杂,不过总算是我们想要的结果了,湘菜、粤菜、川菜、西菜都出来了,每样一个,不重样:
{
  "took": 4,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 9,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "type": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "湘菜",
          "doc_count": 6,
          "rated": {
            "hits": {
              "total": 6,
              "max_score": null,
              "hits": [
                {
                  "_index": "recipes",
                  "_type": "type",
                  "_id": "AVoESHYF_OA-dG63Txsd",
                  "_score": null,
                  "_source": {
                    "name": "鲫鱼汤(变态辣)",
                    "rating": 5,
                    "type": "湘菜"
                  },
                  "sort": [
                    5
                  ]
                }
              ]
            }
          }
        },
        {
          "key": "川菜",
          "doc_count": 1,
          "rated": {
            "hits": {
              "total": 1,
              "max_score": null,
              "hits": [
                {
                  "_index": "recipes",
                  "_type": "type",
                  "_id": "AVoESHYr_OA-dG63Txsf",
                  "_score": null,
                  "_source": {
                    "name": "鱼香肉丝",
                    "rating": 2,
                    "type": "川菜"
                  },
                  "sort": [
                    2
                  ]
                }
              ]
            }
          }
        },
        {
          "key": "粤菜",
          "doc_count": 1,
          "rated": {
            "hits": {
              "total": 1,
              "max_score": null,
              "hits": [
                {
                  "_index": "recipes",
                  "_type": "type",
                  "_id": "AVoESHYW_OA-dG63Txse",
                  "_score": null,
                  "_source": {
                    "name": "广式鲫鱼汤",
                    "rating": 5,
                    "type": "粤菜"
                  },
                  "sort": [
                    5
                  ]
                }
              ]
            }
          }
        },
        {
          "key": "西菜",
          "doc_count": 1,
          "rated": {
            "hits": {
              "total": 1,
              "max_score": null,
              "hits": [
                {
                  "_index": "recipes",
                  "_type": "type",
                  "_id": "AVoESHY3_OA-dG63Txsg",
                  "_score": null,
                  "_source": {
                    "name": "奶油鲍鱼汤",
                    "rating": 2,
                    "type": "西菜"
                  },
                  "sort": [
                    2
                  ]
                }
              ]
            }
          }
        }
      ]
    }
  }
}
上面的实现方法,前面已经说了,可以做,有局限性,那看看新的字段折叠法如何做到呢,查询如下,加一个 collapse 参数,指定对那个字段去重就行了,这里当然对菜系“type”字段进行去重了:
GET recipes/type/_search
{
"query": {
"match": {
"name": "鱼"
}
},
"collapse": {
"field": "type"
},
"size": 3,
"from": 0
}
结果很理想嘛,命中结果还是熟悉的那个味道(和查询结果长的一样嘛),如下:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 9,
"max_score": null,
"hits": [
{
"_index": "recipes",
"_type": "type",
"_id": "AVoDNlRJ_OA-dG63TxpW",
"_score": 0.018980097,
"_source": {
"name": "鲫鱼汤(微辣)",
"rating": 4,
"type": "湘菜"
},
"fields": {
"type": [
"湘菜"
]
}
},
{
"_index": "recipes",
"_type": "type",
"_id": "AVoDNlRk_OA-dG63TxpZ",
"_score": 0.013813315,
"_source": {
"name": "鱼香肉丝",
"rating": 2,
"type": "川菜"
},
"fields": {
"type": [
"川菜"
]
}
},
{
"_index": "recipes",
"_type": "type",
"_id": "AVoDNlRb_OA-dG63TxpY",
"_score": 0.0125863515,
"_source": {
"name": "广式鲫鱼汤",
"rating": 5,
"type": "粤菜"
},
"fields": {
"type": [
"粤菜"
]
}
}
]
}
}
我再试试翻页,把 from 改一下,现在返回了3条数据,from 改成3,新的查询如下:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 9,
"max_score": null,
"hits": [
{
"_index": "recipes",
"_type": "type",
"_id": "AVoDNlRw_OA-dG63Txpa",
"_score": 0.012546891,
"_source": {
"name": "奶油鲍鱼汤",
"rating": 2,
"type": "西菜"
},
"fields": {
"type": [
"西菜"
]
}
}
]
}
}
上面的结果只有一条了,去重之后本来就只有4条数据,上面的工作正常,每个菜系只有一个菜啊,那我不乐意了,帮我每个菜系里面多返回几条,我好选菜啊,加上参数 inner_hits 来控制返回的条数,这里返回2条,按 rating 也排个序,新的查询构造如下:
GET recipes/type/_search
{
"query": {
"match": {
"name": "鱼"
}
},
"collapse": {
"field": "type",
"inner_hits": {
"name": "top_rated",
"size": 2,
"sort": [
{
"rating": "desc"
}
]
}
},
"sort": [
{
"rating": {
"order": "desc"
}
}
],
"size": 2,
"from": 0
}
查询结果如下,完美:
{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 9,
    "max_score": null,
    "hits": [
      {
        "_index": "recipes",
        "_type": "type",
        "_id": "AVoESHYF_OA-dG63Txsd",
        "_score": null,
        "_source": {
          "name": "鲫鱼汤(变态辣)",
          "rating": 5,
          "type": "湘菜"
        },
        "fields": {
          "type": [
            "湘菜"
          ]
        },
        "sort": [
          5
        ],
        "inner_hits": {
          "top_rated": {
            "hits": {
              "total": 6,
              "max_score": null,
              "hits": [
                {
                  "_index": "recipes",
                  "_type": "type",
                  "_id": "AVoESHYF_OA-dG63Txsd",
                  "_score": null,
                  "_source": {
                    "name": "鲫鱼汤(变态辣)",
                    "rating": 5,
                    "type": "湘菜"
                  },
                  "sort": [
                    5
                  ]
                },
                {
                  "_index": "recipes",
                  "_type": "type",
                  "_id": "AVoESHX7_OA-dG63Txsc",
                  "_score": null,
                  "_source": {
                    "name": "鲫鱼汤(微辣)",
                    "rating": 4,
                    "type": "湘菜"
                  },
                  "sort": [
                    4
                  ]
                }
              ]
            }
          }
        }
      },
      {
        "_index": "recipes",
        "_type": "type",
        "_id": "AVoESHYW_OA-dG63Txse",
        "_score": null,
        "_source": {
          "name": "广式鲫鱼汤",
          "rating": 5,
          "type": "粤菜"
        },
        "fields": {
          "type": [
            "粤菜"
          ]
        },
        "sort": [
          5
        ],
        "inner_hits": {
          "top_rated": {
            "hits": {
              "total": 1,
              "max_score": null,
              "hits": [
                {
                  "_index": "recipes",
                  "_type": "type",
                  "_id": "AVoESHYW_OA-dG63Txse",
                  "_score": null,
                  "_source": {
                    "name": "广式鲫鱼汤",
                    "rating": 5,
                    "type": "粤菜"
                  },
                  "sort": [
                    5
                  ]
                }
              ]
            }
          }
        }
      }
    ]
  }
}
好了,字段折叠介绍就到这里。
继续阅读 »
199aon3omgg1vjpg.jpg

 在 Elasticsearch 5.x 有一个字段折叠(Field Collapsing,#22337)的功能非常有意思,在这里分享一下,
 
字段折叠是一个很有历史的需求了,可以看这个 issue,编号#256,最初是2010年7月提的issue,也是讨论最多的帖子之一(240+评论),熬了6年才支持的特性,你说牛不牛,哈哈。
 
目测该特性将于5.3发布,尝鲜地址:Elasticsearch-5.3.0-SNAPSHOT,文档地址:search-request-collapse
 
So,什么是字段折叠,可以理解就是按特定字段进行合并去重,比如我们有一个菜谱搜索,我希望按菜谱的“菜系”字段进行折叠,即返回结果每个菜系都返回一个结果,也就是按菜系去重,我搜索关键字“鱼”,要去返回的结果里面各种菜系都有,有湘菜,有粤菜,有中餐,有西餐,别全是湘菜,就是这个意思,通过按特定字段折叠之后,来丰富搜索结果的多样性。
 
说到这里,有人肯定会想到,使用 term agg+ top hits agg 来实现啊,这种组合两种聚和的方式可以实现上面的功能,不过也有一些局限性,比如,不能分页,#4915;结果不够精确(top term+top hits,es 的聚合实现选择了牺牲精度来提高速度);数据量大的情况下,聚合比较慢,影响搜索体验。
 
而新的的字段折叠的方式是怎么实现的的呢,有这些要点:
  1. 折叠+取 inner_hits 分两阶段执行(组合聚合的方式只有一个阶段),所以 top hits 永远是精确的。
  2. 字段折叠只在 top hits 层执行,不需要每次都在完整的结果集上对为每个折叠主键计算实际的 doc values 值,只对 top hits 这小部分数据操作就可以,和 term agg 相比要节省很多内存。
  3. 因为只在 top hits 上进行折叠,所以相比组合聚合的方式,速度要快很多。
  4. 折叠 top docs 不需要使用全局序列(global ordinals)来转换 string,相比 agg 这也节省了很多内存。
  5. 分页成为可能,和常规搜索一样,具有相同的局限,先获取 from+size 的内容,再合并。
  6. search_after 和 scroll 暂未实现,不过具备可行性。
  7.  折叠只影响搜索结果,不影响聚合,搜索结果的 total 是所有的命中纪录数,去重的结果数未知(无法计算)。

 
下面来看看具体的例子,就知道怎么回事了,使用起来很简单。
  • 先准备索引和数据,这里以菜谱为例,name:菜谱名,type 为菜系,rating 为用户的累积平均评分

DELETE recipes
PUT recipes
POST recipes/type/_mapping
{
"properties": {
"name":{
"type": "text"
},
"rating":{
"type": "float"
},"type":{
"type": "keyword"
}
}
}
POST recipes/type/
{
"name":"清蒸鱼头","rating":1,"type":"湘菜"
}

POST recipes/type/
{
"name":"剁椒鱼头","rating":2,"type":"湘菜"
}

POST recipes/type/
{
"name":"红烧鲫鱼","rating":3,"type":"湘菜"
}

POST recipes/type/
{
"name":"鲫鱼汤(辣)","rating":3,"type":"湘菜"
}

POST recipes/type/
{
"name":"鲫鱼汤(微辣)","rating":4,"type":"湘菜"
}

POST recipes/type/
{
"name":"鲫鱼汤(变态辣)","rating":5,"type":"湘菜"
}

POST recipes/type/
{
"name":"广式鲫鱼汤","rating":5,"type":"粤菜"
}

POST recipes/type/
{
"name":"鱼香肉丝","rating":2,"type":"川菜"
}

POST recipes/type/
{
"name":"奶油鲍鱼汤","rating":2,"type":"西菜"

  • 现在我们看看普通的查询效果是怎么样的,搜索关键字带“鱼”的菜,返回3条数据

POST recipes/type/_search
{
"query": {"match": {
"name": "鱼"
}},"size": 3
全是湘菜,我的天,最近上火不想吃辣,这个第一页的结果对我来说就是垃圾,如下:
{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 9,
    "max_score": 0.26742277,
    "hits": [
      {
        "_index": "recipes",
        "_type": "type",
        "_id": "AVoESHYF_OA-dG63Txsd",
        "_score": 0.26742277,
        "_source": {
          "name": "鲫鱼汤(变态辣)",
          "rating": 5,
          "type": "湘菜"
        }
      },
      {
        "_index": "recipes",
        "_type": "type",
        "_id": "AVoESHXO_OA-dG63Txsa",
        "_score": 0.19100356,
        "_source": {
          "name": "红烧鲫鱼",
          "rating": 3,
          "type": "湘菜"
        }
      },
      {
        "_index": "recipes",
        "_type": "type",
        "_id": "AVoESHWy_OA-dG63TxsZ",
        "_score": 0.19100356,
        "_source": {
          "name": "剁椒鱼头",
          "rating": 2,
          "type": "湘菜"
        }
      }
    ]
  }
}
我们再看看,这次我想加个评分排序,大家都喜欢的是那些,看看有没有喜欢吃的,执行查询:
POST recipes/type/_search
{
"query": {"match": {
"name": "鱼"
}},"sort": [
{
"rating": {
"order": "desc"
}
}
],"size": 3
结果稍微好点了,不过3个里面2个是湘菜,还是有点不合适,结果如下:
{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 9,
    "max_score": null,
    "hits": [
      {
        "_index": "recipes",
        "_type": "type",
        "_id": "AVoESHYF_OA-dG63Txsd",
        "_score": null,
        "_source": {
          "name": "鲫鱼汤(变态辣)",
          "rating": 5,
          "type": "湘菜"
        },
        "sort": [
          5
        ]
      },
      {
        "_index": "recipes",
        "_type": "type",
        "_id": "AVoESHYW_OA-dG63Txse",
        "_score": null,
        "_source": {
          "name": "广式鲫鱼汤",
          "rating": 5,
          "type": "粤菜"
        },
        "sort": [
          5
        ]
      },
      {
        "_index": "recipes",
        "_type": "type",
        "_id": "AVoESHX7_OA-dG63Txsc",
        "_score": null,
        "_source": {
          "name": "鲫鱼汤(微辣)",
          "rating": 4,
          "type": "湘菜"
        },
        "sort": [
          4
        ]
      }
    ]
  }
}
现在我知道了,我要看看其他菜系,这家不是还有西餐、广东菜等各种菜系的么,来来,帮我每个菜系来一个菜看看,换 terms agg 先得到唯一的 term 的 bucket,再组合 top_hits agg,返回按评分排序的第一个 top hits,有点复杂,没关系,看下面的查询就知道了:
GET recipes/type/_search
{
"query": {
"match": {
"name": "鱼"
}
},
"sort": [
{
"rating": {
"order": "desc"
}
}
],"aggs": {
"type": {
"terms": {
"field": "type",
"size": 10
},"aggs": {
"rated": {
"top_hits": {
"sort": [{
"rating": {"order": "desc"}
}],
"size": 1
}
}
}
}
},
"size": 0,
"from": 0
看下面的结果,虽然 json 结构有点复杂,不过总算是我们想要的结果了,湘菜、粤菜、川菜、西菜都出来了,每样一个,不重样:
{
  "took": 4,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 9,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "type": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "湘菜",
          "doc_count": 6,
          "rated": {
            "hits": {
              "total": 6,
              "max_score": null,
              "hits": [
                {
                  "_index": "recipes",
                  "_type": "type",
                  "_id": "AVoESHYF_OA-dG63Txsd",
                  "_score": null,
                  "_source": {
                    "name": "鲫鱼汤(变态辣)",
                    "rating": 5,
                    "type": "湘菜"
                  },
                  "sort": [
                    5
                  ]
                }
              ]
            }
          }
        },
        {
          "key": "川菜",
          "doc_count": 1,
          "rated": {
            "hits": {
              "total": 1,
              "max_score": null,
              "hits": [
                {
                  "_index": "recipes",
                  "_type": "type",
                  "_id": "AVoESHYr_OA-dG63Txsf",
                  "_score": null,
                  "_source": {
                    "name": "鱼香肉丝",
                    "rating": 2,
                    "type": "川菜"
                  },
                  "sort": [
                    2
                  ]
                }
              ]
            }
          }
        },
        {
          "key": "粤菜",
          "doc_count": 1,
          "rated": {
            "hits": {
              "total": 1,
              "max_score": null,
              "hits": [
                {
                  "_index": "recipes",
                  "_type": "type",
                  "_id": "AVoESHYW_OA-dG63Txse",
                  "_score": null,
                  "_source": {
                    "name": "广式鲫鱼汤",
                    "rating": 5,
                    "type": "粤菜"
                  },
                  "sort": [
                    5
                  ]
                }
              ]
            }
          }
        },
        {
          "key": "西菜",
          "doc_count": 1,
          "rated": {
            "hits": {
              "total": 1,
              "max_score": null,
              "hits": [
                {
                  "_index": "recipes",
                  "_type": "type",
                  "_id": "AVoESHY3_OA-dG63Txsg",
                  "_score": null,
                  "_source": {
                    "name": "奶油鲍鱼汤",
                    "rating": 2,
                    "type": "西菜"
                  },
                  "sort": [
                    2
                  ]
                }
              ]
            }
          }
        }
      ]
    }
  }
}
上面的实现方法,前面已经说了,可以做,有局限性,那看看新的字段折叠法如何做到呢,查询如下,加一个 collapse 参数,指定对那个字段去重就行了,这里当然对菜系“type”字段进行去重了:
GET recipes/type/_search
{
"query": {
"match": {
"name": "鱼"
}
},
"collapse": {
"field": "type"
},
"size": 3,
"from": 0
}
结果很理想嘛,命中结果还是熟悉的那个味道(和查询结果长的一样嘛),如下:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 9,
"max_score": null,
"hits": [
{
"_index": "recipes",
"_type": "type",
"_id": "AVoDNlRJ_OA-dG63TxpW",
"_score": 0.018980097,
"_source": {
"name": "鲫鱼汤(微辣)",
"rating": 4,
"type": "湘菜"
},
"fields": {
"type": [
"湘菜"
]
}
},
{
"_index": "recipes",
"_type": "type",
"_id": "AVoDNlRk_OA-dG63TxpZ",
"_score": 0.013813315,
"_source": {
"name": "鱼香肉丝",
"rating": 2,
"type": "川菜"
},
"fields": {
"type": [
"川菜"
]
}
},
{
"_index": "recipes",
"_type": "type",
"_id": "AVoDNlRb_OA-dG63TxpY",
"_score": 0.0125863515,
"_source": {
"name": "广式鲫鱼汤",
"rating": 5,
"type": "粤菜"
},
"fields": {
"type": [
"粤菜"
]
}
}
]
}
}
我再试试翻页,把 from 改一下,现在返回了3条数据,from 改成3,新的查询如下:
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 9,
"max_score": null,
"hits": [
{
"_index": "recipes",
"_type": "type",
"_id": "AVoDNlRw_OA-dG63Txpa",
"_score": 0.012546891,
"_source": {
"name": "奶油鲍鱼汤",
"rating": 2,
"type": "西菜"
},
"fields": {
"type": [
"西菜"
]
}
}
]
}
}
上面的结果只有一条了,去重之后本来就只有4条数据,上面的工作正常,每个菜系只有一个菜啊,那我不乐意了,帮我每个菜系里面多返回几条,我好选菜啊,加上参数 inner_hits 来控制返回的条数,这里返回2条,按 rating 也排个序,新的查询构造如下:
GET recipes/type/_search
{
"query": {
"match": {
"name": "鱼"
}
},
"collapse": {
"field": "type",
"inner_hits": {
"name": "top_rated",
"size": 2,
"sort": [
{
"rating": "desc"
}
]
}
},
"sort": [
{
"rating": {
"order": "desc"
}
}
],
"size": 2,
"from": 0
}
查询结果如下,完美:
{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 9,
    "max_score": null,
    "hits": [
      {
        "_index": "recipes",
        "_type": "type",
        "_id": "AVoESHYF_OA-dG63Txsd",
        "_score": null,
        "_source": {
          "name": "鲫鱼汤(变态辣)",
          "rating": 5,
          "type": "湘菜"
        },
        "fields": {
          "type": [
            "湘菜"
          ]
        },
        "sort": [
          5
        ],
        "inner_hits": {
          "top_rated": {
            "hits": {
              "total": 6,
              "max_score": null,
              "hits": [
                {
                  "_index": "recipes",
                  "_type": "type",
                  "_id": "AVoESHYF_OA-dG63Txsd",
                  "_score": null,
                  "_source": {
                    "name": "鲫鱼汤(变态辣)",
                    "rating": 5,
                    "type": "湘菜"
                  },
                  "sort": [
                    5
                  ]
                },
                {
                  "_index": "recipes",
                  "_type": "type",
                  "_id": "AVoESHX7_OA-dG63Txsc",
                  "_score": null,
                  "_source": {
                    "name": "鲫鱼汤(微辣)",
                    "rating": 4,
                    "type": "湘菜"
                  },
                  "sort": [
                    4
                  ]
                }
              ]
            }
          }
        }
      },
      {
        "_index": "recipes",
        "_type": "type",
        "_id": "AVoESHYW_OA-dG63Txse",
        "_score": null,
        "_source": {
          "name": "广式鲫鱼汤",
          "rating": 5,
          "type": "粤菜"
        },
        "fields": {
          "type": [
            "粤菜"
          ]
        },
        "sort": [
          5
        ],
        "inner_hits": {
          "top_rated": {
            "hits": {
              "total": 1,
              "max_score": null,
              "hits": [
                {
                  "_index": "recipes",
                  "_type": "type",
                  "_id": "AVoESHYW_OA-dG63Txse",
                  "_score": null,
                  "_source": {
                    "name": "广式鲫鱼汤",
                    "rating": 5,
                    "type": "粤菜"
                  },
                  "sort": [
                    5
                  ]
                }
              ]
            }
          }
        }
      }
    ]
  }
}
好了,字段折叠介绍就到这里。 收起阅读 »

Elastic Stack 5.2.0 发布

本周三,Elastic 发布了 ElasticStack 的全新版本5.2.0,包含了很多激动人心的特性,让我们 一起来看看吧,
(Elastic Stack 包括 Elasticsearch、Logstash、Kibana、Beats):
 Elasticsearch 5.2.0 主要亮点:
  1. 新增数字和日期范围字段类型,非常方便对范围类型进行交并集的查询,比如你的数据是日历类型的数据,每天都有一些会议信息,会议的开始和结束时间都不同,你想看本周那天有空,可以使用 range fields 很方便的进行查询。了解更多
  2. 新增分片分配解释 API,会告知分片失败的具体原因,如分片损坏、磁盘写满还是配置错误,进行快速运维,以前只能根据经验到处寻找可能是什么问题,费事费力,了解更多
  3. 对 Keyword 类型标准化,在5.0将 string 类型拆成了 text 和 keyword两种类型,text 支持分词,keyword 则不分词默认支持 doc values,不过有时候你还需要对 keyword 类型进行一些标准化处理,如都转成小写,现在可以使用 normalizers 参数来指定标准化的 filter。
  4. Terms 聚合的分区,terms 聚合默认返回10个 term,以前如果你需要返回全部的 term 列表是不可能的任务(基于内存压力),现在你可以通过将请求分区,以多次请求的方式来取回这些数据,了解更多
  5. 字段折叠,在搜索时可以按某个字段的值进行折叠,在每个折叠的值内进行排序选取 topN,了解更多

 
相关链接:
Download Elasticsearch 5.2.0
Elasticsearch 5.2.0 release notes
Elasticsearch 5.2.0 breaking changes
X-Pack 5.2.0 release notes
 
Logstash 5.2.0 主要亮点:
  1. 新的监控 UI,现在 X-Pack 也能监控 logstash 了,X-Pack 基础免费版就包括,如下图:
    MonitoringUI-rel-blog.png
    Screen_Shot_2017-01-09_at_16.51_.49_.png
  2. 更多的监控 API,新增3个类型的统计信息:cgroup、持久化队列和 output新增持续时间字段。
  3. 离线插件管理,在很多没有公网的部署环境,都需要离线安装,以前的离线安装不够完善,尽管大部分插件没问题,但是还是存在个别插件的依赖链下载不完整的问题,为了解决这个问题,我们基本上重新设计了整个工作流程使用了新的方式来打包插件和他所有的依赖,了解更多

 
相关连接:
Download Logstash 5.2.0
Logstash 5.2.0 release notes
 
Kibana 5.2.0 主要亮点:
  1. 支持 Elasticsearch Tribe 节点,在“admin”集群的基础上,引入了新的“data”集群,“data”集群可以理解成 Kibana 后面的数据来源,可以是 tribe 节点,而“admin”集群是存放 kibana 可视化信息“。kibana”索引的地方,默认 data 和 admin 集群都是在同一个集群,且不能是 tribe 节点,目前还有一些细节正在处理,如 console 还不能很好的工作。
  2. 增加新的可视化类型:热点图(heatmap),可以很方便的按区间和按时间来显示数据的范围分布,如下图:
    Heatmap_Linechart.png
  3. 开始进行国际化的支持,感谢 IBM 团队的努力,目前已经提供了基础的框架支持,虽然是万里长征的第一大步,但也是非常激动人心的。
  4. 地图服务的改进,Elastic 自己的 Tile 地图服务已经上线几个月了,我们现在能提供10个级别的缩放了,X-Pack 基础用户可以达到12个级别的缩放,并且我们正在尝试18个级别的缩放,并且从5.2开始,我们能让这些级别动态调整,不用发布新的 Kibana。
  5. 监控容器中的 Elasticsearch,现在我们可以监控容器里面的 Elasticsearch 实例的运行情况了,CPU 利用率、GC、堆栈使用情况等,如下图:
    monitoring-elasticsearch-in-containers.png

 
相关连接:
Download Kibana 5.2.0
Kibana 5.2.0 release notes
 
Beats 5.2.0 主要亮点:
  1. 新增 Beat:Heartbeat,一个新的正式的官方beat 成员,用于可用性监控,和所有的 beat 一样,轻量级,Heartbeat 可以用于很多场景,比如安全,你不希望暴露某个端口时,使用 Heartbeat,当你发现该端口对外开启了,就可以触发通知,或者服务/网站可用性检测,服务down 了可以及时感知,目前支持:ICMP、TCP 和 HTTP 类型的监控,目前 Heartbeat还处于 beat 阶段,暂不推荐用于生产环境。
  2. Metricbeat 可跟踪网络连接,从5.2开始,Metricbeat 导出了 linux 系统的应用程序的网络连接信息,每个进程打开的 tcp 套接字,本地及远程的 ip 都包含在内,基于它,你可以进行如下的图分析:
    connections-2.png
  3. 收集Prometheus导出的指标,从5.2开始,监控系统普罗米修斯的收集模块导出的数据可以提供给 Metricbeat 然后索引进 Elasticsearch。

 
相关连接:
Download Beats 5.2.0
Beats 5.2.0 release notes
 
Elastic Stack 下载链接:https://www.elastic.co/downloads
Bug 反馈:http://github.com/elastic

以后有版本的更新消息都会在这里发布一份中文版,欢迎大家关注。
继续阅读 »
本周三,Elastic 发布了 ElasticStack 的全新版本5.2.0,包含了很多激动人心的特性,让我们 一起来看看吧,
(Elastic Stack 包括 Elasticsearch、Logstash、Kibana、Beats):
 Elasticsearch 5.2.0 主要亮点:
  1. 新增数字和日期范围字段类型,非常方便对范围类型进行交并集的查询,比如你的数据是日历类型的数据,每天都有一些会议信息,会议的开始和结束时间都不同,你想看本周那天有空,可以使用 range fields 很方便的进行查询。了解更多
  2. 新增分片分配解释 API,会告知分片失败的具体原因,如分片损坏、磁盘写满还是配置错误,进行快速运维,以前只能根据经验到处寻找可能是什么问题,费事费力,了解更多
  3. 对 Keyword 类型标准化,在5.0将 string 类型拆成了 text 和 keyword两种类型,text 支持分词,keyword 则不分词默认支持 doc values,不过有时候你还需要对 keyword 类型进行一些标准化处理,如都转成小写,现在可以使用 normalizers 参数来指定标准化的 filter。
  4. Terms 聚合的分区,terms 聚合默认返回10个 term,以前如果你需要返回全部的 term 列表是不可能的任务(基于内存压力),现在你可以通过将请求分区,以多次请求的方式来取回这些数据,了解更多
  5. 字段折叠,在搜索时可以按某个字段的值进行折叠,在每个折叠的值内进行排序选取 topN,了解更多

 
相关链接:
Download Elasticsearch 5.2.0
Elasticsearch 5.2.0 release notes
Elasticsearch 5.2.0 breaking changes
X-Pack 5.2.0 release notes
 
Logstash 5.2.0 主要亮点:
  1. 新的监控 UI,现在 X-Pack 也能监控 logstash 了,X-Pack 基础免费版就包括,如下图:
    MonitoringUI-rel-blog.png
    Screen_Shot_2017-01-09_at_16.51_.49_.png
  2. 更多的监控 API,新增3个类型的统计信息:cgroup、持久化队列和 output新增持续时间字段。
  3. 离线插件管理,在很多没有公网的部署环境,都需要离线安装,以前的离线安装不够完善,尽管大部分插件没问题,但是还是存在个别插件的依赖链下载不完整的问题,为了解决这个问题,我们基本上重新设计了整个工作流程使用了新的方式来打包插件和他所有的依赖,了解更多

 
相关连接:
Download Logstash 5.2.0
Logstash 5.2.0 release notes
 
Kibana 5.2.0 主要亮点:
  1. 支持 Elasticsearch Tribe 节点,在“admin”集群的基础上,引入了新的“data”集群,“data”集群可以理解成 Kibana 后面的数据来源,可以是 tribe 节点,而“admin”集群是存放 kibana 可视化信息“。kibana”索引的地方,默认 data 和 admin 集群都是在同一个集群,且不能是 tribe 节点,目前还有一些细节正在处理,如 console 还不能很好的工作。
  2. 增加新的可视化类型:热点图(heatmap),可以很方便的按区间和按时间来显示数据的范围分布,如下图:
    Heatmap_Linechart.png
  3. 开始进行国际化的支持,感谢 IBM 团队的努力,目前已经提供了基础的框架支持,虽然是万里长征的第一大步,但也是非常激动人心的。
  4. 地图服务的改进,Elastic 自己的 Tile 地图服务已经上线几个月了,我们现在能提供10个级别的缩放了,X-Pack 基础用户可以达到12个级别的缩放,并且我们正在尝试18个级别的缩放,并且从5.2开始,我们能让这些级别动态调整,不用发布新的 Kibana。
  5. 监控容器中的 Elasticsearch,现在我们可以监控容器里面的 Elasticsearch 实例的运行情况了,CPU 利用率、GC、堆栈使用情况等,如下图:
    monitoring-elasticsearch-in-containers.png

 
相关连接:
Download Kibana 5.2.0
Kibana 5.2.0 release notes
 
Beats 5.2.0 主要亮点:
  1. 新增 Beat:Heartbeat,一个新的正式的官方beat 成员,用于可用性监控,和所有的 beat 一样,轻量级,Heartbeat 可以用于很多场景,比如安全,你不希望暴露某个端口时,使用 Heartbeat,当你发现该端口对外开启了,就可以触发通知,或者服务/网站可用性检测,服务down 了可以及时感知,目前支持:ICMP、TCP 和 HTTP 类型的监控,目前 Heartbeat还处于 beat 阶段,暂不推荐用于生产环境。
  2. Metricbeat 可跟踪网络连接,从5.2开始,Metricbeat 导出了 linux 系统的应用程序的网络连接信息,每个进程打开的 tcp 套接字,本地及远程的 ip 都包含在内,基于它,你可以进行如下的图分析:
    connections-2.png
  3. 收集Prometheus导出的指标,从5.2开始,监控系统普罗米修斯的收集模块导出的数据可以提供给 Metricbeat 然后索引进 Elasticsearch。

 
相关连接:
Download Beats 5.2.0
Beats 5.2.0 release notes
 
Elastic Stack 下载链接:https://www.elastic.co/downloads
Bug 反馈:http://github.com/elastic

以后有版本的更新消息都会在这里发布一份中文版,欢迎大家关注。 收起阅读 »

发现的一个不错的elasticsearch 官方文档的翻译文档

这几天一直在学习elasticsearch,很多地方不是太明白,于是去官方网站上查看说明文档,发现真的很不方便查看,一是由于文档布局排版不好,查看不同的API还得必须跳到不同页面上,最重要一点是需要翻墙才能看文档,很是烦恼,今天忽然在一个网站上发现了一个把elasticsearch官方2.3.3的java elasticsearch 文档翻译了,而且我看了一下,还是不错的,于是分享给大家,果断收藏啊:
Elasticsearch 2.3.3 JAVA api说明文档
继续阅读 »
这几天一直在学习elasticsearch,很多地方不是太明白,于是去官方网站上查看说明文档,发现真的很不方便查看,一是由于文档布局排版不好,查看不同的API还得必须跳到不同页面上,最重要一点是需要翻墙才能看文档,很是烦恼,今天忽然在一个网站上发现了一个把elasticsearch官方2.3.3的java elasticsearch 文档翻译了,而且我看了一下,还是不错的,于是分享给大家,果断收藏啊:
Elasticsearch 2.3.3 JAVA api说明文档 收起阅读 »

Elasticsearch 安全加固 101

images.jpeg

 最近 MongoDB 的安全事件闹得沸沸扬扬,应该不少人都听说了吧,事情大概是,因为 MongoDB 默认的安全设置造成了数据外泄并且被黑客勒索才能找回数据,想了解的,这里有几个链接:
[url=http://mt.sohu.com/20170107/n478047698.shtml]http://mt.sohu.com/20170107/n478047698.shtml​[/url] 
[url=http://www.jianshu.com/p/48d17a69e190]http://www.jianshu.com/p/48d17a69e190​[/url] 
[url=http://bbs.tianya.cn/post-itinfo-503786-1.shtml]http://bbs.tianya.cn/post-itinfo-503786-1.shtml​[/url] 
 
安全从来不是等到出事才要注意的事情,可以说安全是第一重要的事情,不管你是公司的CTO、技术总监、运维总监、架构师还是一线工程师,都应该有安全意识,好了,废话不多说了,Elasticsearch 的用户现在越来越多了,有些已经成为公司的基础服务,所以数据的安全非常重要,今天主要给大家介绍 Elasticsearch 围绕安全方面的的几点使用事项:
 
下载安装
 
     请使用正规渠道下载 Elasticsearch,首选官方网站,下载完成,记得要验证下载文件的 sha1值和官网下载的提供的sha1值进行对比,避免下载过程中被人拦截破坏文件,甚至注入恶意代码。
不要随便安装第三方的插件,插件有可能引入安全漏洞甚至本身自带后门,需谨慎使用。
    链接君:https://www.elastic.co/downloads 
 
 
使用最新的 Elasticsearch
 
    请关注 Elastic 网站,及时更新升级 Elasticsearch 的最新版本,Elasticsearch 每次版本发布都会优化和改进一部分功能,尤其是安全漏洞的补丁,仔细阅读 Elasticsearch 的更新记录,Elasticsearch 的版本遵照 语义化版本 ,所以小版本间应该是能够无缝升级的,建议及时本地测试和线上更新,升级前,记得 snapshot 做好备份。
    链接君:https://www.elastic.co/downloads
 
 
修改默认的 Elasticsearch 集群名称
 
     Elasticsearch 默认的集群名称是 elasticsearch,请在生成环境上一定要修改成其他的名称,并且不同的环境和不同的集群要保证不相同,监控集群节点情况,如果有未知节点加入,一定要及时预警。
    文档君:https://www.elastic.co/guide/e ... .name
 
 不要暴露 Elasticsearch 在公网上
 
      Elasticsearch 默认端口是9200,绑定的是本机127.0.0.1的这个 ip,这个默认参数其实很安全,但是有很多人想要绑定其他的 lan 口或者公网的 ip,可以修改相应参数,记住,修改有风险,如果确实需要将 Elasticsearch 暴露在公网环境,请修改特定的端口绑定IP,不要直接修改参数: network.host,而是要分别修改:http.port 来绑定 HTTP 协议9200 端口的 IP(RESTful 接口调用),修改:transport.tcp.port 对应的 TCP 9300 端口的 IP(集群内通信),如果你不需要 http 端口,你干脆禁用掉,另外还需要在 Elasticsearch 之上加上成熟的安全防护措施(注意是成熟的!),在这里提供几种方案:
  1. 9200的 HTTP 接口之上加上 Nginx 来提供 Http Basic-Auth 的基本的身份认证,辅助 SSL 证书进行传输层的加密,Nginx 进一步限制可接受 Verb 请求类型及可被操作的索引前缀。
  2. 使用 Elastic 的 X-Pack 插件,同样提供了 Http Basic-Auth 和 SSL 传输层的加密,X-Pack 还能提供内外 Elasticsearch 集群节点间的流量加密,避免旁路攻击。

 
     文档君:https://www.elastic.co/guide/e ... tings 
 
禁用批量删除索引
 
Elasticsearch 支持通过_all(全部)和通配符(*)来批量删除索引,在生产环境,这个有点危险,你可以通过设置: action.destructive_requires_name: true 来禁用它。

安全使用动态脚本

     Elasticsearch 的脚本很方便的可以对数据进行操作,不过如果你暂时没有用上,还请禁用它(Elasticsearch 在1.2.x 以后已经默认禁用了),如果你已经在使用动态脚本,比如 Groovy,它不是沙盒机制的脚本引擎,启用 inline 或 store 类型的groovy 有安全风险,请限制脚本的接触方,比如通过模板的方式来限制脚本的调用,只需要执行特定预先定义好的脚本,对调用参数进行过滤和参数值的检测,做好验证,同时各种日志都必须要保留好,方便进行日志分析,异常的调用和请求一定要有发现和预警机制。
      Elasticsearch 默认启用了  Java Security Manager ,但还请正确配置其白名单。
      使用 Groovy 或者JavaScript 等脚本的用户,尽快迁移到 Painless 脚本,Painless 更快更安全。
      文档君:https://www.elastic.co/guide/e ... .html
 
给 Elasticsearch 服务器加固
 
     服务器加固是一个必备流程,不管上面运行的是什么服务;
     首先,请开启防火墙,请设置防火墙规则,只开启必备的端口,完成之后,使用扫描工具扫描服务器,检查端口开发情况;
     如果可能,不要用密码的方法来远程登录服务器,使用公私钥的方式来 ssh 登录服务器,如果只能使用密码,请妥善保管好你的用户名和密码,禁用 root 用户,不用使用弱密码。
     关注 Java 最新的漏洞,使用安全的 JVM 运行时。
     服务器及时更新最新的软件,使用安全的 repo 软件源,绑定软件源的 host和 ip,避免 dns 污染造成的攻击,关注服务器软件漏洞,及时打上补丁。
     收集系统日志和安装相应的入侵检测软件,及时发现服务器是否有异常行为。
 
不要以 root 身份运行 Elasticsearch

    如果你的运维人员打算以 root 身份来运行某个服务,这个运维人员一定是一个不合格的运维人员,记住一定不要以 root 身份来运行 Elasticsearch,另外,要不和其他的服务公用相同的用户,然后还要保证该用户的权限要最小化。
     范例君:
sudo -u es-user ES_JAVA_OPTS="-Xms1024m -Xmx1024m"  /opt/elasticsearch/bin/elasticsearc

 
正确设置 Elasticsearch 的数据目录
 
     请确保 Elasticsearch 的目录分配了合理的读写权限,避免使用共享文件系统,确保只有 elasticsearch 的启动用户才能访问,同理,日志目录也一样需要正确配置,避免泄露敏感信息。
     文档君:https://www.elastic.co/guide/e ... tings
 
定期对 Elasticsearch 进行备份
 
     使用 Elasticsearch 提供的备份还原机制,定期对 Elasticsearch 的数据进行快照备份,以备不时之需。
     文档君:https://www.elastic.co/guide/e ... .html
 
加上监控和预警
 
     Elasticsearch 提供了很好的默认参数,对参数方面还做了正确性检测,bootstrap 启动检查,不准确的参数,直接不允许 Elasticsearch 启动,以至于有很多人抱怨,怎么现在部署到线上默认就需要做这么多设置才能使用呢,是的,以前启动就默认绑定了所有的网卡,集群见自动发现和相连,现在需要手动绑定局域网网卡,默认只是绑定的本机127.0.0.1的 ip,对上线来说麻烦了一点,做了这些检查也就是为了保证数据安全,以前很多的公网都能直接访问的 Elasticsearch 实例,都是因为默认设置就绑定了公网 ip,但是这些还不够,作为用户,你还需要收集各种日志和系统监控信息,及时主动掌握服务健康和资源使用情况,发现异常情况要及时处理,这里提供一些方案:
  1. 使用开源的 Elastic Stack 收集这些日志,可以使用 Filebeat 收集日志,Metricbeat收集系统监控信息,存进 Elasticsearch,一旦发现异常的波动,使用 Watcher 来进行预警,通过邮件或者 webhook 调用短信、微信或者电话。
  2. 使用其他厂商的安全监控产品。
  3. 使用托管的 Elasticsearch 云的产品,如 Elastic Cloud等等。


是的,把安全这个事情考虑进去之后,很多事情都要比没考虑要变得更加复杂和麻烦,千里之堤毁于蚁穴,一个不起眼的忽视就有可能造成全部数据的丢失和泄露,出来混迟早是要还的,安全问题千万不能忽视。
 
以上几点建议举例针对 linux 平台,其他平台思路基本上一样,仅供参考,安全是一个包含很多方方面面的学科,抛砖引玉,希望大家有用。 

最后,Elastic 非常关心我们的产品安全,如果您发现有任何安全方面的问题,还请在这里上报:
https://www.elastic.co/community/security
企业用户需要 X-Pack 及 Elastic 官方技术支持,请访问下面的链接:
https://www.elastic.co/cn/contact
 
继续阅读 »
images.jpeg

 最近 MongoDB 的安全事件闹得沸沸扬扬,应该不少人都听说了吧,事情大概是,因为 MongoDB 默认的安全设置造成了数据外泄并且被黑客勒索才能找回数据,想了解的,这里有几个链接:
[url=http://mt.sohu.com/20170107/n478047698.shtml]http://mt.sohu.com/20170107/n478047698.shtml​[/url] 
[url=http://www.jianshu.com/p/48d17a69e190]http://www.jianshu.com/p/48d17a69e190​[/url] 
[url=http://bbs.tianya.cn/post-itinfo-503786-1.shtml]http://bbs.tianya.cn/post-itinfo-503786-1.shtml​[/url] 
 
安全从来不是等到出事才要注意的事情,可以说安全是第一重要的事情,不管你是公司的CTO、技术总监、运维总监、架构师还是一线工程师,都应该有安全意识,好了,废话不多说了,Elasticsearch 的用户现在越来越多了,有些已经成为公司的基础服务,所以数据的安全非常重要,今天主要给大家介绍 Elasticsearch 围绕安全方面的的几点使用事项:
 
下载安装
 
     请使用正规渠道下载 Elasticsearch,首选官方网站,下载完成,记得要验证下载文件的 sha1值和官网下载的提供的sha1值进行对比,避免下载过程中被人拦截破坏文件,甚至注入恶意代码。
不要随便安装第三方的插件,插件有可能引入安全漏洞甚至本身自带后门,需谨慎使用。
    链接君:https://www.elastic.co/downloads 
 
 
使用最新的 Elasticsearch
 
    请关注 Elastic 网站,及时更新升级 Elasticsearch 的最新版本,Elasticsearch 每次版本发布都会优化和改进一部分功能,尤其是安全漏洞的补丁,仔细阅读 Elasticsearch 的更新记录,Elasticsearch 的版本遵照 语义化版本 ,所以小版本间应该是能够无缝升级的,建议及时本地测试和线上更新,升级前,记得 snapshot 做好备份。
    链接君:https://www.elastic.co/downloads
 
 
修改默认的 Elasticsearch 集群名称
 
     Elasticsearch 默认的集群名称是 elasticsearch,请在生成环境上一定要修改成其他的名称,并且不同的环境和不同的集群要保证不相同,监控集群节点情况,如果有未知节点加入,一定要及时预警。
    文档君:https://www.elastic.co/guide/e ... .name
 
 不要暴露 Elasticsearch 在公网上
 
      Elasticsearch 默认端口是9200,绑定的是本机127.0.0.1的这个 ip,这个默认参数其实很安全,但是有很多人想要绑定其他的 lan 口或者公网的 ip,可以修改相应参数,记住,修改有风险,如果确实需要将 Elasticsearch 暴露在公网环境,请修改特定的端口绑定IP,不要直接修改参数: network.host,而是要分别修改:http.port 来绑定 HTTP 协议9200 端口的 IP(RESTful 接口调用),修改:transport.tcp.port 对应的 TCP 9300 端口的 IP(集群内通信),如果你不需要 http 端口,你干脆禁用掉,另外还需要在 Elasticsearch 之上加上成熟的安全防护措施(注意是成熟的!),在这里提供几种方案:
  1. 9200的 HTTP 接口之上加上 Nginx 来提供 Http Basic-Auth 的基本的身份认证,辅助 SSL 证书进行传输层的加密,Nginx 进一步限制可接受 Verb 请求类型及可被操作的索引前缀。
  2. 使用 Elastic 的 X-Pack 插件,同样提供了 Http Basic-Auth 和 SSL 传输层的加密,X-Pack 还能提供内外 Elasticsearch 集群节点间的流量加密,避免旁路攻击。

 
     文档君:https://www.elastic.co/guide/e ... tings 
 
禁用批量删除索引
 
Elasticsearch 支持通过_all(全部)和通配符(*)来批量删除索引,在生产环境,这个有点危险,你可以通过设置: action.destructive_requires_name: true 来禁用它。

安全使用动态脚本

     Elasticsearch 的脚本很方便的可以对数据进行操作,不过如果你暂时没有用上,还请禁用它(Elasticsearch 在1.2.x 以后已经默认禁用了),如果你已经在使用动态脚本,比如 Groovy,它不是沙盒机制的脚本引擎,启用 inline 或 store 类型的groovy 有安全风险,请限制脚本的接触方,比如通过模板的方式来限制脚本的调用,只需要执行特定预先定义好的脚本,对调用参数进行过滤和参数值的检测,做好验证,同时各种日志都必须要保留好,方便进行日志分析,异常的调用和请求一定要有发现和预警机制。
      Elasticsearch 默认启用了  Java Security Manager ,但还请正确配置其白名单。
      使用 Groovy 或者JavaScript 等脚本的用户,尽快迁移到 Painless 脚本,Painless 更快更安全。
      文档君:https://www.elastic.co/guide/e ... .html
 
给 Elasticsearch 服务器加固
 
     服务器加固是一个必备流程,不管上面运行的是什么服务;
     首先,请开启防火墙,请设置防火墙规则,只开启必备的端口,完成之后,使用扫描工具扫描服务器,检查端口开发情况;
     如果可能,不要用密码的方法来远程登录服务器,使用公私钥的方式来 ssh 登录服务器,如果只能使用密码,请妥善保管好你的用户名和密码,禁用 root 用户,不用使用弱密码。
     关注 Java 最新的漏洞,使用安全的 JVM 运行时。
     服务器及时更新最新的软件,使用安全的 repo 软件源,绑定软件源的 host和 ip,避免 dns 污染造成的攻击,关注服务器软件漏洞,及时打上补丁。
     收集系统日志和安装相应的入侵检测软件,及时发现服务器是否有异常行为。
 
不要以 root 身份运行 Elasticsearch

    如果你的运维人员打算以 root 身份来运行某个服务,这个运维人员一定是一个不合格的运维人员,记住一定不要以 root 身份来运行 Elasticsearch,另外,要不和其他的服务公用相同的用户,然后还要保证该用户的权限要最小化。
     范例君:
sudo -u es-user ES_JAVA_OPTS="-Xms1024m -Xmx1024m"  /opt/elasticsearch/bin/elasticsearc

 
正确设置 Elasticsearch 的数据目录
 
     请确保 Elasticsearch 的目录分配了合理的读写权限,避免使用共享文件系统,确保只有 elasticsearch 的启动用户才能访问,同理,日志目录也一样需要正确配置,避免泄露敏感信息。
     文档君:https://www.elastic.co/guide/e ... tings
 
定期对 Elasticsearch 进行备份
 
     使用 Elasticsearch 提供的备份还原机制,定期对 Elasticsearch 的数据进行快照备份,以备不时之需。
     文档君:https://www.elastic.co/guide/e ... .html
 
加上监控和预警
 
     Elasticsearch 提供了很好的默认参数,对参数方面还做了正确性检测,bootstrap 启动检查,不准确的参数,直接不允许 Elasticsearch 启动,以至于有很多人抱怨,怎么现在部署到线上默认就需要做这么多设置才能使用呢,是的,以前启动就默认绑定了所有的网卡,集群见自动发现和相连,现在需要手动绑定局域网网卡,默认只是绑定的本机127.0.0.1的 ip,对上线来说麻烦了一点,做了这些检查也就是为了保证数据安全,以前很多的公网都能直接访问的 Elasticsearch 实例,都是因为默认设置就绑定了公网 ip,但是这些还不够,作为用户,你还需要收集各种日志和系统监控信息,及时主动掌握服务健康和资源使用情况,发现异常情况要及时处理,这里提供一些方案:
  1. 使用开源的 Elastic Stack 收集这些日志,可以使用 Filebeat 收集日志,Metricbeat收集系统监控信息,存进 Elasticsearch,一旦发现异常的波动,使用 Watcher 来进行预警,通过邮件或者 webhook 调用短信、微信或者电话。
  2. 使用其他厂商的安全监控产品。
  3. 使用托管的 Elasticsearch 云的产品,如 Elastic Cloud等等。


是的,把安全这个事情考虑进去之后,很多事情都要比没考虑要变得更加复杂和麻烦,千里之堤毁于蚁穴,一个不起眼的忽视就有可能造成全部数据的丢失和泄露,出来混迟早是要还的,安全问题千万不能忽视。
 
以上几点建议举例针对 linux 平台,其他平台思路基本上一样,仅供参考,安全是一个包含很多方方面面的学科,抛砖引玉,希望大家有用。 

最后,Elastic 非常关心我们的产品安全,如果您发现有任何安全方面的问题,还请在这里上报:
https://www.elastic.co/community/security
企业用户需要 X-Pack 及 Elastic 官方技术支持,请访问下面的链接:
https://www.elastic.co/cn/contact
  收起阅读 »

招聘

招聘需求:
 
技术总监1名:
1、 日志分析产品研发经验优先,8年以上工作经验
2、 精通elasticsearch、Redis、MongoDB、Neo4J等NoSQL系统,熟悉elasticsearch集群管理和性能调优,有在实际项目中使用搜索引擎工具、内存数据库、文档数据库、图数据库的经验
3、 熟悉Hadoop、Spark、Spark Streaming、Storm、HBase、ZooKeeper等大数据生态系统组件;熟悉Kafka、ZeroMQ等消息系统组件
4、 精通日志处理工具集ELK,flume,heka等
5、 熟悉Linux环境,熟练使用Python和Shell进行脚本编程
6、 精通JAVA语言,熟悉主流开源框架Struts2、Spring、Hibernate,SpringMVC的运行机制及使用。熟练掌握和使用J2EE开发中常见面向对象设计模式(Singleton,Proxy,Factory等)
7、 有系统运维管理平台项目开发及管理经验优先
8、 提供优厚待遇及期权,薪水50万以上
9、 金融行业背景优先考虑
 
 
技术专家2名:
1、熟悉Hadoop生态圈相关技术,如Hbase,Hive,Zookeeper,flume,kafka,storm
2、了解spark运行机制,研读spark部分内核源码;了解ELK日志分析平台(elasticsearch、logstash、kibana)使用
3、 熟悉Linux系统的基本操作和集群环境的搭建和部署
4、 熟悉JavaEE的开发,掌握JavaEE流行框架的使用,如:Struts2、Spring、Hibernate、SpringMVC等
5、熟悉主流数据库Oracle、DB2、MySQL、Mariadb的使用及性能优化;会使用NoSql数据库(如redis)解决开发过程中遇到的业务问题
6、提供优厚待遇和期权,薪水30万以上
7、金融行业优先考虑
如有意向请联系郝女士   联系电话:13520834022      邮箱:haojinjin16@163.com
招聘单位:洋大数据信息技术(北京)有限公司
继续阅读 »
招聘需求:
 
技术总监1名:
1、 日志分析产品研发经验优先,8年以上工作经验
2、 精通elasticsearch、Redis、MongoDB、Neo4J等NoSQL系统,熟悉elasticsearch集群管理和性能调优,有在实际项目中使用搜索引擎工具、内存数据库、文档数据库、图数据库的经验
3、 熟悉Hadoop、Spark、Spark Streaming、Storm、HBase、ZooKeeper等大数据生态系统组件;熟悉Kafka、ZeroMQ等消息系统组件
4、 精通日志处理工具集ELK,flume,heka等
5、 熟悉Linux环境,熟练使用Python和Shell进行脚本编程
6、 精通JAVA语言,熟悉主流开源框架Struts2、Spring、Hibernate,SpringMVC的运行机制及使用。熟练掌握和使用J2EE开发中常见面向对象设计模式(Singleton,Proxy,Factory等)
7、 有系统运维管理平台项目开发及管理经验优先
8、 提供优厚待遇及期权,薪水50万以上
9、 金融行业背景优先考虑
 
 
技术专家2名:
1、熟悉Hadoop生态圈相关技术,如Hbase,Hive,Zookeeper,flume,kafka,storm
2、了解spark运行机制,研读spark部分内核源码;了解ELK日志分析平台(elasticsearch、logstash、kibana)使用
3、 熟悉Linux系统的基本操作和集群环境的搭建和部署
4、 熟悉JavaEE的开发,掌握JavaEE流行框架的使用,如:Struts2、Spring、Hibernate、SpringMVC等
5、熟悉主流数据库Oracle、DB2、MySQL、Mariadb的使用及性能优化;会使用NoSql数据库(如redis)解决开发过程中遇到的业务问题
6、提供优厚待遇和期权,薪水30万以上
7、金融行业优先考虑
如有意向请联系郝女士   联系电话:13520834022      邮箱:haojinjin16@163.com
招聘单位:洋大数据信息技术(北京)有限公司 收起阅读 »

对话 Kibana 之父:如果需要,你应该自己动手编写工具

转载:http://www.infoq.com/cn/news/2 ... nTool
Elastic 中国开发者大会 2016上,ELK 正式宣布更名为“Elastic Stack”,Elastic公司称其开源项目累计已经有8000万次下载。Elastic Stack 最新版本为5.0,从此,Elastic公司会对Elasticsearch、Kibana、Logstash、Beats、X-Pack进行统一规划以同版本号码发布。会上,Kibana 的原作者 Rashid Khan 进行了题为《Kibana 5.0: The Window into the Elastic Stack》。 PPT下载:http://elasticsearch.cn/article/122 

IMG_4857.gif


早在2001年,Rashid 就接触了运维工作,他的第一份工作是在摩根大通集团做网络运维管理分析员。2012年,Rashid 在美国一家媒体公司担任架构工程师,并且研发了 Kibana 的初始版本,那时他的目的是专门设计界面以适配 Logstash,如今 Kibana 已经逐渐演变成了 Elasticsearch 的分析平台。运维出身的他是在怎样的情况下开始了 Kibana 开发,Kibana 走到今天经历了什么,将来 Kibana 的发展会是怎样的?InfoQ 对 Rashid 进行了采访,以下文章来自于采访稿件的整理。

作为运维人员,我亟须优化日志搜索

开始的时候做运维工作遇到很多问题,on call待命,甚至在凌晨2点被叫醒;这种工作状态让我感到很厌烦。往往,在日志中可以发现问题所在,但是需要花费好久时间才能找到。

于是,我寻找有哪些开源软件可以做基本的日志搜索,然后发现了Logstash和与之配合使用的Elasticsearch。经过测试,我发现Elasticsearch速度很快并且提供我所需要的功能;然后我就开始编写一套非常简单的interface作为补充展示,大概花费了我几天的时间。这就是第一版Kibana的诞生过程,当时是采用PHP编写的,功能是可以展示日志并配有搜索入口,目的是把这个工具可以交付给我的boss,使得他无需我的参与便可以使用这个interface。需要提一句的是,Elasticsearch 对于Web编程很友好,并且日志数据按照日期排列。

在全职投入 Kibana 为 Elastic 公司工作之前,我一直从事运维工作并且我非常喜欢运维工作。因为这段实践经验帮助我体会到了运维人的问题和困难,这让我知道了需要创造一个什么样的工具。我依然认为运维是一个非常有挑战的工作,让所有的东西都正常地运转起来。

编程吧,动手创造自己的工具

的确,我是运维人员,但是我还自己动手开发工具。这在美国越来越普遍了,因为大家意识到,如果你可以编写代码,你的工作会轻松很多,代码可以代替你进行重复工作。通过代码实现自动化是正确的途径,没有人愿意不停地做同样的事情。

编写Kibana是因为我当时没有发现一个适合我的工具,于是我决定自己动手。第一版Kibana是用PHP写的,第二版是用Ruby,第三版之后是用JavaScript。我不害怕学习心得语言,因为学语言并不难,Ruby或者JavaScript的语言掌握仅仅是简单的熟悉语法,并没有接触到实际项目中复杂的事情。而重写Kibana的工作也并不复杂,因为其实Elasticsearch做的工作最重。

“哪种编程语言最好?”说实话,其实这个问题的讨论对我而言并不重要。重要的是,为你的工作选择恰当的语言。PHP在我心中仍然有一席之地,我认为它依然是一个好的语言,可能很多人有异议,但是我认为它简单易上手、稳定变化慢,相关工具也很容易上手。Node.js相对来说,比较复杂;Node社区也意识到这个问题,并且正在改进。比如说,当时我选择了Ruby重写Kibana,是因为Logstash是用JRuby写的,Elasticsearch 使用Java写的(JRuby可以理解为Ruby可以跑在JVM里面)。当时想把 Kibana 的 Ruby那个版本是因为想放到Logstash中,但是没有成功。所以,接下来我们研发了Kibana 3 。

在开发Kibana之前,我用过Graphite,但是为什么依然不满足呢?首先,Graphite很棒,所有关于数字、指标、时间序列的事情。但是那个时候,我需要的是一个可以做日志搜索的东西,需要有一个Dashboard可以给出一个图片。我非常希望从日志中获得信息并且把它们和预定的指标绑定在一起,实际上这些幕后工作都是Elasticsearch做的,并且速度真的快很多。此外需要考虑到扩展性,Graphite对于它适合的大小还算可以,即使超过了极限,更多的数据对应着更多的CPU消耗;但是想扩展很多的话,就很困难了,这一点上Graphite还有很多可以提升的空间,Elastic Stack就可以很轻松地实现。

不过,我依然很喜欢Graphite,我也依然认为这是一个有需求的工具,并且它其实是可以和Elasticsearch、Kibana结合在一起使用的。Architecture dependent的问题困扰了很多人, 比如32bit和64bit两者之间,即便是传输一个文件也不能工作,这是一个非常可怕的事情。Graphite 解决了这个问题,并且界面很美,功能强大 。Kibana也解决了很多相似的问题, 尤其是加上了Elasticsearch的配合,解决了许多我在做运维工作时总是非常想做的工作。

从来没有犹豫过是否开源

12岁的时候就开始接触开源项目了,所以在写Kibana的时候从来没有犹豫过要不要把它开源。

开始的时候我们只是把需求写在纸上,然后一条条做。放到Github之后,看到下载量不断上升我们感到很吃惊。我们没有想到,原来这么多人都面临这同样的问题,没有想到大家对这样的一个开源项目如此需要。开源的目的就是为了能帮助人们,最初我也曾疑惑有可能根本没有人用;然后发现越来越多的人在讨论、使用它。现在Elastic Stack是一个开源整体,把个人的事业career放在服务其他人的开源项目上,并能收获到好的反馈,这让我们感到很开心、很欣慰。

当时的小愿望,现在的大公司

Kibana第一版存在仅仅几周。是因为我开始使用Ruby进行重写,这大概花费了两周的时间。因为Logstash使用Ruby写的(即便当时我并不会Ruby),而我的目的就是让Kibana适配Logstash和Elasticsearch,让三者在一起可以协作获得更多的信息。当时我的想法就是让三个工具可以无缝衔接起来好似一个工具一样,有趣的是,这仅仅是当时我自己的一个愿望,后来Elasticsearch的人联系我问要不要合并在成为同一家公司,我们才发现彼此的看法竟然不谋而合。

elastic-logo-H-full-color.jpg


我现在依然是on call的。在 Elastic 公司,我们有on call轮班制。其实这是与用户交流的机会,这是我们 Elastic 每一个开发者都非常珍视的机会。在对用户支持的过程中,我们可以更清晰地了解用户的需求和真实使用情况;还有一些其他方式,比如会议、沙龙、见面会等,任何可以帮助我们与社区连接的。在我看来,在用户发生问题时,你在他身边并且帮助修复问题:没有比这个更好的工作方式。所以,on call不是折磨,是机会。

Kibana的下一步:数据挖掘、角色报表

1、数据挖掘,精益求精

最开始在做日志分析的那个时候,坦率地讲,我并没有关联到了Data mining。因为那时只是想先把问题弄清楚。但是在把所有的问题都解决完(这些并不难,只是花时间而已),实现了最初我们想要的Kibana之后,运维的工作量就大大减少了。

一切都运转得很顺利之后,我们开始思考怎样能把事情做得越来越好,尽量少地产生问题。我们可以获得数据,并且发现了一些问题发生的规律:问题的发生节点,比如说往往半夜三点、发布新版本之后;问题的发生频率,哪些问题非常热门,我们需要把对应的工作放在CDN上;问题的优化处理,发生问题之后如何最快地回滚。机器学习很强有力,而且对于运维人员而言,越少的红色提示越幸福。但是目前我的考虑是,能做到提前预警就已经很棒了。

基于这些思考,我们认为需要开始进行数据挖掘的工作了,这样才把事情做得越来越好,才能更大程度地帮助公司用户。在五六年前,很少会有人想到运维团队可以给出商业业务的指导意见,但是现在这开始越来越普遍。

2、接下来,Dashboard不会只有public一种

此前Kibana的Dashboard是完全公开的,没有角色区分。我知道一些其他的工具提供了包边权限区分的功能。最初的时候,只是想保持事情的简单化,Kibana并没有考虑到把Dashboard做成基于角色的,我们考虑更多的是产品易用性、功能,而没有打算触及安全模块。对于我们自己而言,这并不是过去那些年优先级第一的事项。最开始Kibana的主要矛盾是怎样把内容展现出来,打造Elasticsearch的良好用户界面,所以那个时候是界面是对所有用户可见的。而权限的控制我们是在Elasticsearch上面实现的,搜索、索引、集群操作添加是在Elasticsearch,也就是说我们首先Elasticsearch中实现数据层的安全。

接下来,我们考虑怎样把安全性延展到Kibana中,对不同角色进行区分化的搜索展示。(此前,有一个插件可以满足在Kibana中进行 Elasticsearch 用户的控制。代码是开源的,任何公司都可以编写自己的安全模块,并且我们也乐意帮助他们)在决定做一件事情之后我们就希望把一件事情做得非常好,而不是半途而废。

Kibana in Elastic Stack 5.0

Snip20170111_11.png


研发情况

研发出新功能的第一版本通常很快,但是需要不断的测试确保所有运转正常。Elastic Stack5.0 的所有功能大概花费了9个月的研发时间。在决策哪些功能需要研发时,我们有几周的考虑时间,还会参考社区中的反馈。然后我们还会给开发者一些自主空间,我们试着避免总是给某些人下发某些任务。我们认为最好主意并不来自与管理层或者经理,而是来自于那些与用户交流频繁的软件工程师,花费很多时间做客户支持的同事。会面通常是远程的,因为我们是个分布式的公司,公司成员分布于30多个国家,一共470多人。Kibana部分的研发、测试和运营人员一共有20多人。

如果有两个程序员所做的事情是一样的话,没有关系这不是重复劳动,反而可以让产品更加优化,两个人可以互相讨论加速功能研发;否则的话产品会被程序员打上过强的个人烙印,最终让产品交付给客户的是整个团队。

会一直并且只是配合Elasticsearch

是的,我们没有其他 datasource 的计划,因为我们大部分的使用case是要有时间序列的。

最开始融合在一起的是 Elasticsearch 和 Logstash,然后 Kibana 参与进来。在这个融合的过程中,遇到任何冲突或者改变,我们的评判标准都是怎样对用户而言更友好。举例说明,安全问题最佳的解决是在数据层,搜索非常占用内存,使用ES可以做很复杂的事情,在旧版本的 Kibana 中,可以使用 Elasticsearch 的 API,但是这拖缓了速度,并且用户可能会做一些危险的事情。在 Kibana 和 Elasticsearch 融合之后,我再也没有那样做了,对于一些重的内存需求工作不会在UI层(Kibana)而是会放到数据层(ES),用最少的内存,让尽可能多的计算脱离 JVM heap ,放入socket breaker,让我们管理更简洁干净并做到在UI可追踪。

Kibana的美学

Kibana最初的设计师只是我一个人,现在当然我们有了自己的很优秀的设计师,这是很被看重的部分,没有外包出去。因为我们需要和设计团队频繁地交流,不断地给予反馈,和工程团队。这是我们公司文化的一个重要部分。

你想一想这是运维人员需要终日面对的工具,没有人愿意一直看着丑的东西;此外,也希望Kibana可以让运维人员的boss们感到惊艳,我们希望可以帮助使用者产生非常美的工作。

写在最后

在采访结束时,InfoQ问Rashid是否可以给广大读者一些建议,Rashid想了想说:


如果你有一个想法,把它code出来,build起来。不要等其他人的开源代码,有可能你会等到,但是有可能你永远等不到。在你写出来之后,你没准会收获惊喜。


 
1.png

 
继续阅读 »
转载:http://www.infoq.com/cn/news/2 ... nTool
Elastic 中国开发者大会 2016上,ELK 正式宣布更名为“Elastic Stack”,Elastic公司称其开源项目累计已经有8000万次下载。Elastic Stack 最新版本为5.0,从此,Elastic公司会对Elasticsearch、Kibana、Logstash、Beats、X-Pack进行统一规划以同版本号码发布。会上,Kibana 的原作者 Rashid Khan 进行了题为《Kibana 5.0: The Window into the Elastic Stack》。 PPT下载:http://elasticsearch.cn/article/122 

IMG_4857.gif


早在2001年,Rashid 就接触了运维工作,他的第一份工作是在摩根大通集团做网络运维管理分析员。2012年,Rashid 在美国一家媒体公司担任架构工程师,并且研发了 Kibana 的初始版本,那时他的目的是专门设计界面以适配 Logstash,如今 Kibana 已经逐渐演变成了 Elasticsearch 的分析平台。运维出身的他是在怎样的情况下开始了 Kibana 开发,Kibana 走到今天经历了什么,将来 Kibana 的发展会是怎样的?InfoQ 对 Rashid 进行了采访,以下文章来自于采访稿件的整理。

作为运维人员,我亟须优化日志搜索

开始的时候做运维工作遇到很多问题,on call待命,甚至在凌晨2点被叫醒;这种工作状态让我感到很厌烦。往往,在日志中可以发现问题所在,但是需要花费好久时间才能找到。

于是,我寻找有哪些开源软件可以做基本的日志搜索,然后发现了Logstash和与之配合使用的Elasticsearch。经过测试,我发现Elasticsearch速度很快并且提供我所需要的功能;然后我就开始编写一套非常简单的interface作为补充展示,大概花费了我几天的时间。这就是第一版Kibana的诞生过程,当时是采用PHP编写的,功能是可以展示日志并配有搜索入口,目的是把这个工具可以交付给我的boss,使得他无需我的参与便可以使用这个interface。需要提一句的是,Elasticsearch 对于Web编程很友好,并且日志数据按照日期排列。

在全职投入 Kibana 为 Elastic 公司工作之前,我一直从事运维工作并且我非常喜欢运维工作。因为这段实践经验帮助我体会到了运维人的问题和困难,这让我知道了需要创造一个什么样的工具。我依然认为运维是一个非常有挑战的工作,让所有的东西都正常地运转起来。

编程吧,动手创造自己的工具

的确,我是运维人员,但是我还自己动手开发工具。这在美国越来越普遍了,因为大家意识到,如果你可以编写代码,你的工作会轻松很多,代码可以代替你进行重复工作。通过代码实现自动化是正确的途径,没有人愿意不停地做同样的事情。

编写Kibana是因为我当时没有发现一个适合我的工具,于是我决定自己动手。第一版Kibana是用PHP写的,第二版是用Ruby,第三版之后是用JavaScript。我不害怕学习心得语言,因为学语言并不难,Ruby或者JavaScript的语言掌握仅仅是简单的熟悉语法,并没有接触到实际项目中复杂的事情。而重写Kibana的工作也并不复杂,因为其实Elasticsearch做的工作最重。

“哪种编程语言最好?”说实话,其实这个问题的讨论对我而言并不重要。重要的是,为你的工作选择恰当的语言。PHP在我心中仍然有一席之地,我认为它依然是一个好的语言,可能很多人有异议,但是我认为它简单易上手、稳定变化慢,相关工具也很容易上手。Node.js相对来说,比较复杂;Node社区也意识到这个问题,并且正在改进。比如说,当时我选择了Ruby重写Kibana,是因为Logstash是用JRuby写的,Elasticsearch 使用Java写的(JRuby可以理解为Ruby可以跑在JVM里面)。当时想把 Kibana 的 Ruby那个版本是因为想放到Logstash中,但是没有成功。所以,接下来我们研发了Kibana 3 。

在开发Kibana之前,我用过Graphite,但是为什么依然不满足呢?首先,Graphite很棒,所有关于数字、指标、时间序列的事情。但是那个时候,我需要的是一个可以做日志搜索的东西,需要有一个Dashboard可以给出一个图片。我非常希望从日志中获得信息并且把它们和预定的指标绑定在一起,实际上这些幕后工作都是Elasticsearch做的,并且速度真的快很多。此外需要考虑到扩展性,Graphite对于它适合的大小还算可以,即使超过了极限,更多的数据对应着更多的CPU消耗;但是想扩展很多的话,就很困难了,这一点上Graphite还有很多可以提升的空间,Elastic Stack就可以很轻松地实现。

不过,我依然很喜欢Graphite,我也依然认为这是一个有需求的工具,并且它其实是可以和Elasticsearch、Kibana结合在一起使用的。Architecture dependent的问题困扰了很多人, 比如32bit和64bit两者之间,即便是传输一个文件也不能工作,这是一个非常可怕的事情。Graphite 解决了这个问题,并且界面很美,功能强大 。Kibana也解决了很多相似的问题, 尤其是加上了Elasticsearch的配合,解决了许多我在做运维工作时总是非常想做的工作。

从来没有犹豫过是否开源

12岁的时候就开始接触开源项目了,所以在写Kibana的时候从来没有犹豫过要不要把它开源。

开始的时候我们只是把需求写在纸上,然后一条条做。放到Github之后,看到下载量不断上升我们感到很吃惊。我们没有想到,原来这么多人都面临这同样的问题,没有想到大家对这样的一个开源项目如此需要。开源的目的就是为了能帮助人们,最初我也曾疑惑有可能根本没有人用;然后发现越来越多的人在讨论、使用它。现在Elastic Stack是一个开源整体,把个人的事业career放在服务其他人的开源项目上,并能收获到好的反馈,这让我们感到很开心、很欣慰。

当时的小愿望,现在的大公司

Kibana第一版存在仅仅几周。是因为我开始使用Ruby进行重写,这大概花费了两周的时间。因为Logstash使用Ruby写的(即便当时我并不会Ruby),而我的目的就是让Kibana适配Logstash和Elasticsearch,让三者在一起可以协作获得更多的信息。当时我的想法就是让三个工具可以无缝衔接起来好似一个工具一样,有趣的是,这仅仅是当时我自己的一个愿望,后来Elasticsearch的人联系我问要不要合并在成为同一家公司,我们才发现彼此的看法竟然不谋而合。

elastic-logo-H-full-color.jpg


我现在依然是on call的。在 Elastic 公司,我们有on call轮班制。其实这是与用户交流的机会,这是我们 Elastic 每一个开发者都非常珍视的机会。在对用户支持的过程中,我们可以更清晰地了解用户的需求和真实使用情况;还有一些其他方式,比如会议、沙龙、见面会等,任何可以帮助我们与社区连接的。在我看来,在用户发生问题时,你在他身边并且帮助修复问题:没有比这个更好的工作方式。所以,on call不是折磨,是机会。

Kibana的下一步:数据挖掘、角色报表

1、数据挖掘,精益求精

最开始在做日志分析的那个时候,坦率地讲,我并没有关联到了Data mining。因为那时只是想先把问题弄清楚。但是在把所有的问题都解决完(这些并不难,只是花时间而已),实现了最初我们想要的Kibana之后,运维的工作量就大大减少了。

一切都运转得很顺利之后,我们开始思考怎样能把事情做得越来越好,尽量少地产生问题。我们可以获得数据,并且发现了一些问题发生的规律:问题的发生节点,比如说往往半夜三点、发布新版本之后;问题的发生频率,哪些问题非常热门,我们需要把对应的工作放在CDN上;问题的优化处理,发生问题之后如何最快地回滚。机器学习很强有力,而且对于运维人员而言,越少的红色提示越幸福。但是目前我的考虑是,能做到提前预警就已经很棒了。

基于这些思考,我们认为需要开始进行数据挖掘的工作了,这样才把事情做得越来越好,才能更大程度地帮助公司用户。在五六年前,很少会有人想到运维团队可以给出商业业务的指导意见,但是现在这开始越来越普遍。

2、接下来,Dashboard不会只有public一种

此前Kibana的Dashboard是完全公开的,没有角色区分。我知道一些其他的工具提供了包边权限区分的功能。最初的时候,只是想保持事情的简单化,Kibana并没有考虑到把Dashboard做成基于角色的,我们考虑更多的是产品易用性、功能,而没有打算触及安全模块。对于我们自己而言,这并不是过去那些年优先级第一的事项。最开始Kibana的主要矛盾是怎样把内容展现出来,打造Elasticsearch的良好用户界面,所以那个时候是界面是对所有用户可见的。而权限的控制我们是在Elasticsearch上面实现的,搜索、索引、集群操作添加是在Elasticsearch,也就是说我们首先Elasticsearch中实现数据层的安全。

接下来,我们考虑怎样把安全性延展到Kibana中,对不同角色进行区分化的搜索展示。(此前,有一个插件可以满足在Kibana中进行 Elasticsearch 用户的控制。代码是开源的,任何公司都可以编写自己的安全模块,并且我们也乐意帮助他们)在决定做一件事情之后我们就希望把一件事情做得非常好,而不是半途而废。

Kibana in Elastic Stack 5.0

Snip20170111_11.png


研发情况

研发出新功能的第一版本通常很快,但是需要不断的测试确保所有运转正常。Elastic Stack5.0 的所有功能大概花费了9个月的研发时间。在决策哪些功能需要研发时,我们有几周的考虑时间,还会参考社区中的反馈。然后我们还会给开发者一些自主空间,我们试着避免总是给某些人下发某些任务。我们认为最好主意并不来自与管理层或者经理,而是来自于那些与用户交流频繁的软件工程师,花费很多时间做客户支持的同事。会面通常是远程的,因为我们是个分布式的公司,公司成员分布于30多个国家,一共470多人。Kibana部分的研发、测试和运营人员一共有20多人。

如果有两个程序员所做的事情是一样的话,没有关系这不是重复劳动,反而可以让产品更加优化,两个人可以互相讨论加速功能研发;否则的话产品会被程序员打上过强的个人烙印,最终让产品交付给客户的是整个团队。

会一直并且只是配合Elasticsearch

是的,我们没有其他 datasource 的计划,因为我们大部分的使用case是要有时间序列的。

最开始融合在一起的是 Elasticsearch 和 Logstash,然后 Kibana 参与进来。在这个融合的过程中,遇到任何冲突或者改变,我们的评判标准都是怎样对用户而言更友好。举例说明,安全问题最佳的解决是在数据层,搜索非常占用内存,使用ES可以做很复杂的事情,在旧版本的 Kibana 中,可以使用 Elasticsearch 的 API,但是这拖缓了速度,并且用户可能会做一些危险的事情。在 Kibana 和 Elasticsearch 融合之后,我再也没有那样做了,对于一些重的内存需求工作不会在UI层(Kibana)而是会放到数据层(ES),用最少的内存,让尽可能多的计算脱离 JVM heap ,放入socket breaker,让我们管理更简洁干净并做到在UI可追踪。

Kibana的美学

Kibana最初的设计师只是我一个人,现在当然我们有了自己的很优秀的设计师,这是很被看重的部分,没有外包出去。因为我们需要和设计团队频繁地交流,不断地给予反馈,和工程团队。这是我们公司文化的一个重要部分。

你想一想这是运维人员需要终日面对的工具,没有人愿意一直看着丑的东西;此外,也希望Kibana可以让运维人员的boss们感到惊艳,我们希望可以帮助使用者产生非常美的工作。

写在最后

在采访结束时,InfoQ问Rashid是否可以给广大读者一些建议,Rashid想了想说:


如果你有一个想法,把它code出来,build起来。不要等其他人的开源代码,有可能你会等到,但是有可能你永远等不到。在你写出来之后,你没准会收获惊喜。


 
1.png

  收起阅读 »

Elasticsearch 2.x mapping tips

elasticsearch 2.x mapping tips

作者:杨振涛  首发于:Elasticsearch 中文社区  日期:2017-1-10

如果把elasticsearch中的mapping类比为关系型数据库中的schema的话,那么我们可能重点强调了两者之间的共性,而忽略了elasticsearch里mapping很不相同的部分 —— 这恰恰是实践中最容易被坑的地方。这里总结了几点实践中的小心得,希望对你所有帮助。

mapping 基础
创建索引库index
curl -XPOST "http://192.168.9.19:9200/vivo_vimc"

查看指定索引库的mapping:



curl -XGET "http://192.168.9.19:9200/vivo_ ... ot%3B
 


PS: 这时你获得的结果为空,因为刚建的库,没有mapping信息。

创建索引类型type并指定mapping :
curl -XPOST http://192.168.9.19:9200/vivo_vmic/apps/_mapping -d '{
"apps" : {
"properties" : {
"appName" : {
"type" : "string",
"index" : "not_analyzed",
"fields" :{
"cn": {
"type" : "string",
"index" : "analyzed",
"analyzer": "ik"
},
"en": {
"type" : "string",
}
},
"store":"yes"
},
"status" : {
"type" : "boolean"
},
"type" : {
"type" : "integer"
},
"onsaleDate" : {
"type" : "date"
},
}
}
}'

更新mapping (只能增加字段,不能删除字段,也不能修改字段类型,或者说无法增加一个不同类型的同名字段):

增加属性 score:
curl -XPOST "http://192.168.9.19:9200/vivo_ ... ot%3B -d '{
"apps": {
"properties": {
"score":{
"type":"float"
}
}
}
}'
   
更新成功会返回:
{
"acknowledged" : true
}


删除mapping :
2.4版本开始ES已经不支持mapping的删除了。

tip1 dynamic 模式

动态mapping是ES的一个重要特性,这个配置的可选值及含义如下:
  • true  :支持动态扩展,新增数据有新的属性时,自动添加,索引成功
  • false :不支持动态扩展,新增数据有新的属性时,直接忽略,索引成功
  • strict: 不支持动态扩展,新增数据有新的属性时,会报错,索引失败



tip2 主要数据类型及注意事项
  • string

    分词和不分词的值都需要,中英文都需要 ,
    长度截取,超长过滤 ,
    大小写问题(不分词时索引数据不会转小写,搜索都会转小写)    
    analyzer: analyzed, not_analyzed, no(表示该属性不能用来做搜索和聚合)
    properties : .raw, .en/.cn
    
  • date :           如果不明确指定,那么默认的date格式是:"strict_date_optional_time||epoch_millis",这是官网的表述,意思是可以是一个字符串类型的输入,也可以是数值类型的输入,前者可以是日期或者日期加上时间,后者则是毫秒数。关于时区信息:不管业务上是否需要时区信息,我们建议依然保存,以防万一。另外,data类型在明确指定 format 参数时,也有很多坑,对于format: epoch_second, epools_millis ,如果你想用来排序,那么为了性能,我们强烈建议你使用 epoc_second,差距很大哟,你可以亲自做一个对比测试。

 
  •  long, integer, short, byte, double ,float 希望此类字段参与搜索和聚合的话,就不能设置not_analyzed。

 
  • boolean, binaryboolean类型比较特殊,在ES里面只定义了false类的值( false, "false", "off", "no", "0", "" , 0, 0.0 ),其他所有都认为是true。实践中,我们建议优先使用 0(编程和性能友好),其次使用 true(兼容json默认的类型)。

 
  •  ipv4 type:ip 日志分析等最常用的数据类型,注意这里的是ipv4,ipv6目前暂不支持(ES 2.x);赋值时其实传递的是字符串,但ES内部其实保存的是一个long类型。

 
  • geo type:geo_point , type:geo_shape  LBS服务的必选数据类型,但不建议完全依赖此特性,业务层面要尽可能地缩小范围,或者在使用围栏类功能时,只要业务容忍,使用正方形代替圆形。

 
  • 数组,对象,内嵌将一个复杂对象放在一个属性中,其中数组最常用。

 
  • completion主要是用来做自动完成和拼写纠错的。



tip3 id设置  

在不设置id的情况下,默认的ES会给一个类似HASH串的随机ID;如果业务上需要且可以保证索引数据的唯一性,也可以使用业务ID作为索引ID,好处就是可以根据业务ID轻松地GET到索引数据,而无需维护索引ID和业务ID的关系。

同时,设置mapping的时候也可以指定ID的生成策略,比如UUID:
curl -s -XPUT http://192.168.9.19:9200/vivo_vimc -d '
{
"mappings": {
"apps": {
"_id": {
"path": "uuid"
},
"properties": {
"cnName": {
"type": "string",
"index": "analyzed"
}
}
}
}
}'


tip4 index和type规划

index的别名这个特性就不再强调了,不管是否用到,第一时间设置别名是最佳实践! schema 比较相似的type,放在同一个index里;schema差异非常大的type,建议放在不同的index里;原因是跟搜索引擎的segment以及lucene有关,本质上同一个index里的type底层是同样的存储结构,差异越大意味着type a的属性在type b里大部分都是空值,那么最终会得到一个非常稀疏的矩阵,影响计算效率并浪费存储空间。

关于滚动index的问题,对于日志类的搜索应用,按天或其他维度做滚动index是非常好必要的,这样可以更好地区分冷热数据。比如:


index                        alias
vivo_appstore_log_20160108  
vivo_appstore_log_20160109  vivo_appstore_log
vivo_appstore_log_20160110  vivo_appstore_log
vivo_appstore_log_20160111  vivo_appstore_log
...



如果只需要查询最近3天的数据,那么只需要对3天前的index remove alias即可,然后每天循环滚动。一个细节是,对于这种场景下的索引,写入的时候必须使用原始的index name,而不能使用alias;查询的时候则使用alias。


另一个问题,就是index容量的规划,副本数直接决定需要多少冗余空间;另外,索引数据本身也会有膨胀的现象,尤其是基于中文的全文搜索应用,term集可能会比较大。比如有10000个docs,占用100MB空间时,并不能简单认为100000个docs就占用约1GB。


tip5 测试分词器

如果使用的是基于词典的分词器,比如IK这类,那么线上系统可能会需要按需添加自定义词,或者同义词等,技术上我们可以暴露该类功能给搜索引擎运营人员使用。所以,需要提供一个测试分词器的接口,方便对比和验证。ES默认就提供这样的REST接口的。

按指定分词器分词指定文本:
GET /vivo_vimc/apps/_analyze?text=Hello, vivo 移动互联网&analyzer=ik

按指定索引库的属性测试分词效果:
GET /vivo_vimc/apps/_analyze
{
"field": "appName",
"text": "Pokemon Go"
}

以上关于 mapping 的几点心得,并非金科玉律,需要根据不同的业务需求场景来区别分析和应对。如果你有更多心得,欢迎回复本文分享。


关于作者:
杨振涛,vivo移动互联网 搜索架构师,关注实时搜索,搜索广告,以及大数据的存储、索引、搜索和可视化。
继续阅读 »
elasticsearch 2.x mapping tips

作者:杨振涛  首发于:Elasticsearch 中文社区  日期:2017-1-10

如果把elasticsearch中的mapping类比为关系型数据库中的schema的话,那么我们可能重点强调了两者之间的共性,而忽略了elasticsearch里mapping很不相同的部分 —— 这恰恰是实践中最容易被坑的地方。这里总结了几点实践中的小心得,希望对你所有帮助。

mapping 基础
创建索引库index
curl -XPOST "http://192.168.9.19:9200/vivo_vimc"

查看指定索引库的mapping:



curl -XGET "http://192.168.9.19:9200/vivo_ ... ot%3B
 


PS: 这时你获得的结果为空,因为刚建的库,没有mapping信息。

创建索引类型type并指定mapping :
curl -XPOST http://192.168.9.19:9200/vivo_vmic/apps/_mapping -d '{
"apps" : {
"properties" : {
"appName" : {
"type" : "string",
"index" : "not_analyzed",
"fields" :{
"cn": {
"type" : "string",
"index" : "analyzed",
"analyzer": "ik"
},
"en": {
"type" : "string",
}
},
"store":"yes"
},
"status" : {
"type" : "boolean"
},
"type" : {
"type" : "integer"
},
"onsaleDate" : {
"type" : "date"
},
}
}
}'

更新mapping (只能增加字段,不能删除字段,也不能修改字段类型,或者说无法增加一个不同类型的同名字段):

增加属性 score:
curl -XPOST "http://192.168.9.19:9200/vivo_ ... ot%3B -d '{
"apps": {
"properties": {
"score":{
"type":"float"
}
}
}
}'
   
更新成功会返回:
{
"acknowledged" : true
}


删除mapping :
2.4版本开始ES已经不支持mapping的删除了。

tip1 dynamic 模式

动态mapping是ES的一个重要特性,这个配置的可选值及含义如下:
  • true  :支持动态扩展,新增数据有新的属性时,自动添加,索引成功
  • false :不支持动态扩展,新增数据有新的属性时,直接忽略,索引成功
  • strict: 不支持动态扩展,新增数据有新的属性时,会报错,索引失败



tip2 主要数据类型及注意事项
  • string

    分词和不分词的值都需要,中英文都需要 ,
    长度截取,超长过滤 ,
    大小写问题(不分词时索引数据不会转小写,搜索都会转小写)    
    analyzer: analyzed, not_analyzed, no(表示该属性不能用来做搜索和聚合)
    properties : .raw, .en/.cn
    
  • date :           如果不明确指定,那么默认的date格式是:"strict_date_optional_time||epoch_millis",这是官网的表述,意思是可以是一个字符串类型的输入,也可以是数值类型的输入,前者可以是日期或者日期加上时间,后者则是毫秒数。关于时区信息:不管业务上是否需要时区信息,我们建议依然保存,以防万一。另外,data类型在明确指定 format 参数时,也有很多坑,对于format: epoch_second, epools_millis ,如果你想用来排序,那么为了性能,我们强烈建议你使用 epoc_second,差距很大哟,你可以亲自做一个对比测试。

 
  •  long, integer, short, byte, double ,float 希望此类字段参与搜索和聚合的话,就不能设置not_analyzed。

 
  • boolean, binaryboolean类型比较特殊,在ES里面只定义了false类的值( false, "false", "off", "no", "0", "" , 0, 0.0 ),其他所有都认为是true。实践中,我们建议优先使用 0(编程和性能友好),其次使用 true(兼容json默认的类型)。

 
  •  ipv4 type:ip 日志分析等最常用的数据类型,注意这里的是ipv4,ipv6目前暂不支持(ES 2.x);赋值时其实传递的是字符串,但ES内部其实保存的是一个long类型。

 
  • geo type:geo_point , type:geo_shape  LBS服务的必选数据类型,但不建议完全依赖此特性,业务层面要尽可能地缩小范围,或者在使用围栏类功能时,只要业务容忍,使用正方形代替圆形。

 
  • 数组,对象,内嵌将一个复杂对象放在一个属性中,其中数组最常用。

 
  • completion主要是用来做自动完成和拼写纠错的。



tip3 id设置  

在不设置id的情况下,默认的ES会给一个类似HASH串的随机ID;如果业务上需要且可以保证索引数据的唯一性,也可以使用业务ID作为索引ID,好处就是可以根据业务ID轻松地GET到索引数据,而无需维护索引ID和业务ID的关系。

同时,设置mapping的时候也可以指定ID的生成策略,比如UUID:
curl -s -XPUT http://192.168.9.19:9200/vivo_vimc -d '
{
"mappings": {
"apps": {
"_id": {
"path": "uuid"
},
"properties": {
"cnName": {
"type": "string",
"index": "analyzed"
}
}
}
}
}'


tip4 index和type规划

index的别名这个特性就不再强调了,不管是否用到,第一时间设置别名是最佳实践! schema 比较相似的type,放在同一个index里;schema差异非常大的type,建议放在不同的index里;原因是跟搜索引擎的segment以及lucene有关,本质上同一个index里的type底层是同样的存储结构,差异越大意味着type a的属性在type b里大部分都是空值,那么最终会得到一个非常稀疏的矩阵,影响计算效率并浪费存储空间。

关于滚动index的问题,对于日志类的搜索应用,按天或其他维度做滚动index是非常好必要的,这样可以更好地区分冷热数据。比如:


index                        alias
vivo_appstore_log_20160108  
vivo_appstore_log_20160109  vivo_appstore_log
vivo_appstore_log_20160110  vivo_appstore_log
vivo_appstore_log_20160111  vivo_appstore_log
...



如果只需要查询最近3天的数据,那么只需要对3天前的index remove alias即可,然后每天循环滚动。一个细节是,对于这种场景下的索引,写入的时候必须使用原始的index name,而不能使用alias;查询的时候则使用alias。


另一个问题,就是index容量的规划,副本数直接决定需要多少冗余空间;另外,索引数据本身也会有膨胀的现象,尤其是基于中文的全文搜索应用,term集可能会比较大。比如有10000个docs,占用100MB空间时,并不能简单认为100000个docs就占用约1GB。


tip5 测试分词器

如果使用的是基于词典的分词器,比如IK这类,那么线上系统可能会需要按需添加自定义词,或者同义词等,技术上我们可以暴露该类功能给搜索引擎运营人员使用。所以,需要提供一个测试分词器的接口,方便对比和验证。ES默认就提供这样的REST接口的。

按指定分词器分词指定文本:
GET /vivo_vimc/apps/_analyze?text=Hello, vivo 移动互联网&analyzer=ik

按指定索引库的属性测试分词效果:
GET /vivo_vimc/apps/_analyze
{
"field": "appName",
"text": "Pokemon Go"
}

以上关于 mapping 的几点心得,并非金科玉律,需要根据不同的业务需求场景来区别分析和应对。如果你有更多心得,欢迎回复本文分享。


关于作者:
杨振涛,vivo移动互联网 搜索架构师,关注实时搜索,搜索广告,以及大数据的存储、索引、搜索和可视化。 收起阅读 »

《Elasticsearch 权威指南》中文版

es-guide.gif

 在几十位社区同学的共同努力下,《Elasticsearch 权威指南》的翻译工作接近尾声,
在线访问链接如下:
http://es-guide-preview.elasticsearch.cn
 
晚点会放到 elastic.co 官网上,大家学习 Elasticsearch 又多了一份好的资料,大家在访问的过程,如果发现有问题(翻译的各种 bug,翻译有误,不合理,不通顺,标点,格式等等),欢迎前往  https://github.com/elasticsear ... guide 提交 Issue,同时也欢迎直接提交 pull request 来改进本书。
 
同时也希望更多的志愿者加入我们一起进行翻译,后续我们会继续翻译其他的手册,另外有很多同学自己已经在翻译部分内容,也欢迎加入我们一起,有兴趣的同学加入我们翻译的QQ群:109764489 ,一起为 Elastic 的中文资料贡献力量。

最后,再次感谢以下本书的志愿者:
薛杰,骆朗,彭秋源,魏喆,饶琛琳, 风虎,路小磊,michealzh,nodexy,sdlyjzh,落英流离, sunyonggang,Singham,烧碱,龙翔,陈思,陈华, 追风侃侃,Geolem,卷发,kfypmqqw,袁伟强,yichao, 小彬,leo,tangmisi,Alex,baifan,Evan,fanyer, wwb,瑞星,刘碧琴,walker,songgl, 吕兵,东,杜宁,秦东亮,biyuhao,刘刚, yumo,王秀文,zcola,gitqh,blackoon,David,韩炳辰, 韩陆,echolihao,Xargin,abel-sun,卞顺强, bsll,冬狼,王琦。
 
继续阅读 »
es-guide.gif

 在几十位社区同学的共同努力下,《Elasticsearch 权威指南》的翻译工作接近尾声,
在线访问链接如下:
http://es-guide-preview.elasticsearch.cn
 
晚点会放到 elastic.co 官网上,大家学习 Elasticsearch 又多了一份好的资料,大家在访问的过程,如果发现有问题(翻译的各种 bug,翻译有误,不合理,不通顺,标点,格式等等),欢迎前往  https://github.com/elasticsear ... guide 提交 Issue,同时也欢迎直接提交 pull request 来改进本书。
 
同时也希望更多的志愿者加入我们一起进行翻译,后续我们会继续翻译其他的手册,另外有很多同学自己已经在翻译部分内容,也欢迎加入我们一起,有兴趣的同学加入我们翻译的QQ群:109764489 ,一起为 Elastic 的中文资料贡献力量。

最后,再次感谢以下本书的志愿者:
薛杰,骆朗,彭秋源,魏喆,饶琛琳, 风虎,路小磊,michealzh,nodexy,sdlyjzh,落英流离, sunyonggang,Singham,烧碱,龙翔,陈思,陈华, 追风侃侃,Geolem,卷发,kfypmqqw,袁伟强,yichao, 小彬,leo,tangmisi,Alex,baifan,Evan,fanyer, wwb,瑞星,刘碧琴,walker,songgl, 吕兵,东,杜宁,秦东亮,biyuhao,刘刚, yumo,王秀文,zcola,gitqh,blackoon,David,韩炳辰, 韩陆,echolihao,Xargin,abel-sun,卞顺强, bsll,冬狼,王琦。
  收起阅读 »

2017年学习内容

  • 重新看lucene源码
  • 看es源码
  • 对比lucene和es
  • 基于lucene实现自己的搜索框架

  • 重新看lucene源码
  • 看es源码
  • 对比lucene和es
  • 基于lucene实现自己的搜索框架

Elastic{ON}DevChina2016 资料下载

本月10号在北京的第一次 Elastic 中国开发者大会的资料现在已经可以下载了,没有去现场的或者去现场的还想回顾的都可以去看看,欢迎大家踊跃交流讨论!
 
https://pan.baidu.com/s/1slbCZ9b

 
本月10号在北京的第一次 Elastic 中国开发者大会的资料现在已经可以下载了,没有去现场的或者去现场的还想回顾的都可以去看看,欢迎大家踊跃交流讨论!
 
https://pan.baidu.com/s/1slbCZ9b