本文参考 ES全文指南翻译版,做出一些学习笔记,顺便修改了一些过时代码。以保证在ES5.51版可用。
Elasticsearch 建立在Lucene基础上的搜索引擎,Lucene 是当今最先进,最高效的全功能开源搜索引擎#框架。
特点:
- 分布式实时文件存储.
- 实时分析的分布式搜索引擎。
- 可以扩展到上百台服务器,处理PB级别的结构化或非结构化数据。
因为ES使用RESTful做接口,那么它不仅是跨平台的,而且也是跨语言的。
安装
可以在此页面安装最新版本的ES
如果你需要安装ELK,那么需要注意版本号,三个版本号必须得是一直的。
ELK就是Elasticsearch && logstash && kibana
运行
进入Elasticsearch目录,执行./bin/elasticsearch
执行上述命令,会在终端保持,如果想在后台运行,可以使用 ./bin/elasticsearch -d
RESTful交互方式可以使用终端自带的Curl,也可以使用postman,kibana的Dev Tools。
默认,开启的是本机9200端口,可以在浏览器输入 "http://localhost:9200/?pretty"
返回信息{
"name" : "e-w08f7",
"cluster_name" : "app",
"cluster_uuid" : "YfLUi2T0QTi36ECLRf3ggA",
"version" : {
"number" : "5.5.1",
"build_hash" : "19c13d0",
"build_date" : "2017-07-18T20:44:24.823Z",
"build_snapshot" : false,
"lucene_version" : "6.6.0"
},
"tagline" : "You Know, for Search"
}
API:
非java语言可以使用resultful风格向本机9200发送请求,例如查询集群总数。
GET _count?pretty 使用kibana的Dev Tools
curl -XGET 'http://localhost:9200/_count?pretty' 使用终端curl命令
- 相应的 HTTP 请求方法 或者 变量 : GET, POST, PUT, HEAD 或者 DELETE。
- 集群中任意一个节点的访问协议、主机名以及端口。
- 请求的路径。
- 任意一个查询后再加上 ?pretty 就可以生成 更加美观 的JSON反馈,以增强可读性。
- 一个 JSON 编码的请求主体(如果需要的话)。
面向文档:
ES是面向文档型数据库,这意味着它存储的是整个对象或者 文档,它不但会存储它们,还会为他们建立索引.
ES 使用json做为文档序列化的格式.一个json对象可以理解为一个文档.
索引
这里的索引是一个动词,不是一个名词,区别与mysql的索引。
例子:
想象我们正在为一个名叫 megacorp 的公司的 HR 部门制作一个新的员工名单系统,这些名单应该可以满足实时协同工作,所以它应该可以满足以下要求:
- 数据可以包含多个值的标签、数字以及纯文本内容,
- 可以检索任何职员的所有数据。
- 允许结构化搜索。例如,查找30岁以上的员工。
- 允许简单的全文搜索以及相对复杂的短语搜索。
- 在返回的匹配文档中高亮关键字。
- 拥有数据统计与管理的后台。
结构化搜索可以理解为搜索一个类型,比如上文的30岁以上员工(where age > 30),比如只查找女性(where sex = 2),全文检索分两部分,一个是检索词,一个是文档,在存储为文档的时候,会将文档分词,拆分为一个一个的词语,检索词在检索时也会查分成一个一个词语,然后进行匹配。在查询的时候,可以通过参数获取高亮关键字。
关键字:索引、类型、文档
此处的索引相当于mysql的数据库,可以有多个索引,类型相当于数据表,文档就是一行一行数据,每个文档都代表一个员工.
操作流程:
- 为每一个员工的 文档 创建索引,每个 文档 都包含了一个员工的所有信息。
- 每个文档都会被标记为 employee 类型。
- 这种类型将存活在 megacorp 这个 索引 中。
- 这个索引将会存储在 Elasticsearch 的集群中
索引(数据库)为megacorp,类型(数据表)为employee,文档(列)就是每个员工的信息.
创建一个员工文档,并保存在megacorp索引中的employee类型下,不需要显示的创建,会在创建的过程中设定默认值。
PUT /megacorp/employee/1
{
"first_name" : "John",
"last_name" : "Smith",
"age" : 25,
"about" : "I love to go rock climbing",
"interests": [ "sports", "music" ]
}
返回信息.
此处可以看到,created的值为true,因为我已经创建过1的员工,如果再创建一次,created的值就会为false。
检索文档:
- 检索第一个员工,这里没有进行全文检索只是查询第一个员工,格式为GET /megacorp/employee/1
GET的HTTP操作方式,这里为读取,megacorp为索引名,employee为类型名,1为要查询的数据.
结果如下:
这里可以看到两个不同的命令,一个是PUT一个是GET,一个表示插入,一个表示读取,如果希望删除,则将GET修改为DELETE,如果希望查看是否存在,则使用HEAD,如果是更新数据,则还是使用PUT,数据格式同上。右侧可以看到我们想要的数据.
简易搜索
- 搜索整个类型下所有内容
GET /megacorp/employee/_search 表示搜索employee下的所有文档
右侧有几个关键词,total表示一共有多少个文档,hits表示所有文档,__index表示所属哪个索引,
__type表示为哪个类型.
- 搜索 姓氏包含Smith
GET /megacorp/employee/_search?q=last_name:Smith queryString方式.
不过query string方式有其局限性,比如说过滤器等等,可以采用更灵活、方便的 Query DSL方式.
GET /megacorp/employee/_search
{
"query" : {
"match" : {
"last_name" : "Smith"
}
}
}
这里使用了json作为查询条件,更为简洁干净。
更加复杂的搜索
查询条件为,last_name =Smith,并且年纪大于30。
GET megacorp/employee/_search
{
"query": {
"bool": {
"must": { "match": {"last_name":"Fir"} },
"filter": {
"range": {
"age": {
"gte": 30
}
}
}
}
}
}
以上demo工作在5.51版本。
全文搜索
搜索所有喜欢climbing(攀岩)的员工
GET megacorp/employee/_search
{
"query": {
"match": {
"about": "climbing" #这里测试时最好是多个词,因为es会进行拆分再进行匹配
}
}
}
精确匹配
返回精确匹配员工
GET /megacorp/employee/_search
{
"query" : {
"match_phrase" : {
"about" : "rock climbing"
}
}
}
高亮关键字
增加highlight参数
GET /megacorp/employee/_search
{
"query" : {
"match_phrase" : {
"about" : "rock climbing"
}
},
"highlight": {
"fields" : {
"about" : {}
}
}
}
汇总、统计
员工中最受欢迎的兴趣是什么:
GET /megacorp/employee/_search
{
"aggs": {
"all_interests": {
"terms": { "field": "interests" }
}
}
}
在执行以上查询时会发生错误
Fielddata is disabled on text fields by default. Set fielddata=true on [interests] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead
5.x后对排序,聚合这些操作用单独的数据结构(fielddata)缓存到内存里了,需要单独开启.
执行以下操作
PUT megacorp/_mapping/employee/
{
"properties": {
"interests": {
"type": "text",
"fielddata": true
}
}
}
上图右侧展示了,喜欢音乐的有4个,喜欢运动的有3个等等。
查找姓smith的兴趣汇总
GET /megacorp/employee/_search
{
"query": {
"match": {
"last_name": "smith"
}
},
"aggs": {
"all_interests": {
"terms": { "field": "interests" }
}
}
}
只需要加上刚才的query参数.
每个兴趣下的平均年龄
GET /megacorp/employee/_search
{
"query": {
"match": {
"last_name": "smith"
}
},
"aggs": {
"all_interests": {
"terms": { "field": "interests" },
"aggs": {
"age_avg": {
"avg": {
"field": "age"
}
}
}
}
}
}
只需要在aggs下的terms后面增加aggs参数,aggs里的age_avg可以自定义。