介绍

Elasticsearch 是一个分布式的免费开源搜索和分析引擎,适用于包括文本、数字、地理空间、结构化和非结构化数据等在内的所有类型的数据。

官方文档

官方介绍

其特点是:

  • 一个分布式的实时文档存储,每个字段 可以被索引与搜索
  • 一个分布式实时分析搜索引擎
  • 能胜任上百个服务节点的扩展,并支持 PB 级别的结构化或者非结构化数据

基本概念

1、Index(索引)

动词:相当于MySQL的insert;

名词:相当于MySQL的Database。

2、Type(类型)

在Index中,可以定义一个或多个类型。类似于MySQL中的Table,每一种类型的数据放在一起。

3、Document(文档)

保存在某个索引(Index)下,某种类型(Type)的一个数据(Document),文档是JSON格式的,Document就像是MySQL中的某个Table里面的内容。

4、倒排索引

在存储数据时,ES会将整句拆分为单词,以单词来反向检索整句。

docker安装ES

docker安装elasticsearch

初步检索

1、_cat

GET/_cat/nodes    //查看所有节点
GET/_cat/health   //查看es健康状况
GET/_cat/master   //查看主节点
GET/_cat/indices  //查看所有索引

2、索引一个文档(保存)

//在customer索引下的external类型下保存1号数据为
PUT customer/external/1
{
    "name":"John Doe"
}

PUT和POST都可以:

  • POST新增。如果不指定id,会自动生成id。指定id就会修改这个数据,并新增版本号。
  • PUT可以新增可以修改。PUT必须指定id,由于PUT需要指定id,我们一般用来做修改操作,不指定id会报错。

3、查询文档

GET customer/external/1

//结果:
{ 
  "_index" : "customer",    //索引
  "_type" : "external",     //类型
  "_id" : "1",              //记录id
  "_version" : 1,           //版本号
  "_seq_no" : 0,            //并发控制字段,每次更新就会+1,用来做乐观锁
  "_primary_term" : 1,      //同上,主分片重新分配,如重启,就会变化
  "found" : true,
  "_source" : {
    "name" : "John Doe"
  }
}

//可以用_seq_no和_primary_term做并发时的乐观锁
//在更新时携带当前的这两个值,后台更新时如发现这两个值已经变化了(即更新过)则会更新失败
//?if_seq_no=1&if_primary_term=1

4、更新文档

//该方法会对比原来数据,如果数据与原来一样,则什么都不做
POST customer/external/1/_update
{
    "doc" : {
        "name":"John Doew"
    }
}

//或者 不带update则不会检查原数据,会一直更新
POST customer/external/1
{
    "name":"John Doe2"
}

//或者
PUT customer/external/1
{
    "name":"John Doe2"
}

//更新同时增加属性  不带update也可以
POST customer/external/1/_update
{
    "doc":{"name":"Jane Doe","age":20}
}

5、删除文档&索引

//删除文档
DELETE customer/external/1
//删除索引  不能直接删除类型
DELETE customer

6、bulk批量API

POST customer/external/_bulk
{"index":{"_id":"1"}}
{"name":"John Doe"}
{"index":{"_id":"2"}}
{"name":"John Doe"}

//语法格式
{action:{metadata}}\n
{request body}\n

进阶检索

1.准备

为了测试更复杂的情况,需要将官方提供的测试数据用批量命令进行导入。

//命令是
POST bank/account/_bulk
//后跟上面的测试数据

2. 基本语法

//查询语句的典型结构
{
    QUERY_NAME:{
        ARGUMENT:VALUE,
        ARGUMENT:VALUE,
    }
}

//例子
GET bank/_search
{
  //查询条件
  "query": {
    "match_all": {}   
  },
  //排序方式
  "sort": [
    {
      "account_number": "asc"
    } ,
    {
      "balance": "desc"
    }
  ],
  //分页
  "from": 0,
  "size": 20,
  //显示哪些信息
  "_source": ["balance", "firstname"]
}

3. match

全文匹配,如果是数值类型会进行完全匹配,如果是字符串类型则会对检索条件进行分词匹配,返回的结果会按得分从高到低排列。

如果字符串类型的要匹配精确的值,可在字段后面加上.keyword

GET bank/_search
{
  "query": {
    "match": {
      "balance": 16418
    }
  }
}

//查到了19条记录
GET bank/_search
{
  "query": {
    "match": {
      "address": "Mill lane"
    }
  }
}

4. math_phrase

短语匹配,将需要匹配的值当成一个整体单词(不分词)进行检索。

//只能查到一条记录
GET bank/_search
{
  "query": {
    "match_phrase": {
      "address": "Mill lane"
    }
  }
}

5. multi_match

多字段匹配,即多个字段匹配检索条件。

//address和city会分别与mill和movico进行匹配
GET bank/_search
{
  "query": {
    "multi_match": {
      "query": "mill movico",
      "fields": ["address","city"]
    }
  }
}

6. bool复合查询

GET bank/_search
{
  "query": {
    "bool": {
      //必须满足
      "must": [
        {
          "match": {
            "gender": "M"
          }
        },
        {  
          "match": {
            "address": "mill"
          }
        }
      ],
      //必须不是  相当于过滤器
      "must_not": [
        {
          "match": {
            "age": 28
          }
        }
      ],
      //应该满足 满足了分数会相应提高,不满足不会被过滤掉
      "should": [
        {
          "match": {
            "lastname": "Hines"
          }
        }
      ]
    }
  }
}

7. filter

//filter就是一个过滤器.能够对查询到的结果进行过滤,且不会贡献相关性得分
GET bank/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "range": {
            "age": {
              "gte": 10,
              "lte": 20
            }
          }
        }
      ]
    }
  }
}

8. term

和match一样,匹配某个属性的值。

建议:全文检索字段用match,其他非text字段匹配用term

GET bank/_search
{
  "query": {
    "term": {
      "balance": {
        "value": 32838
      }
    }
  }
}

//完全匹配,不能查到数据
GET bank/_search
{
  "query": {
    "match": {
      "address.keyword": "798 Farragut"
    }
  }
}
//对比上面,短语匹配,能查到一条数据
GET bank/_search
{
  "query": {
    "match_phrase": {
      "address": "798 Farragut"
    }
  }
}

聚合(aggregations)

聚合提供了从数据中分组和提取数据的能力。最简单的聚合方法大致等于SQL GROUP BY和SQL聚合函数。在ES中,执行搜索会返回hits(命中结果),并且同时返回聚合结果,把一个响应中的所有hits分隔开的能力。

//搜索address中包含mill的所有人的年龄分布以及平均年龄
GET bank/_search
{
  "query": {
    "match": {
      "address": "mill"
    }
  },
  "aggs": {
    "ageAgg": {
      "terms": {
        "field": "age",
        "size": 10
      }
    },
    "ageAvg":{
      "avg": {
        "field": "age"
      }
    }
  }
}

//返回的聚合结果为
"aggregations" : {
    "ageAgg" : {
        "doc_count_error_upper_bound" : 0,
        "sum_other_doc_count" : 0,
        "buckets" : [
            {
                "key" : 38,
                "doc_count" : 2
            },
            {
                "key" : 28,
                "doc_count" : 1
            },
            {
                "key" : 32,
                "doc_count" : 1
            }
        ]
    },
    "ageAvg" : {
        "value" : 34.0
    }
}


//按照年龄聚合,并且请求这些年龄段的平均薪资
GET bank/_search
{
  "query": {
    "match_all": {}
  },
  "aggs": {
    "ageAgg": {
      "terms": {
        "field": "age",
        "size": 3
      },
      "aggs": {
        "avgAgg": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
}
//返回的结果
"aggregations" : {
    "ageAgg" : {
        "doc_count_error_upper_bound" : 0,
        "sum_other_doc_count" : 820,
        "buckets" : [
            {
                "key" : 31,
                "doc_count" : 61,
                "avgAgg" : {
                    "value" : 28312.918032786885
                }
            },
            {
                "key" : 39,
                "doc_count" : 60,
                "avgAgg" : {
                    "value" : 25269.583333333332
                }
            },
            {
                "key" : 26,
                "doc_count" : 59,
                "avgAgg" : {
                    "value" : 23194.813559322032
                }
            }
        ]
    }
}

映射(Mapping)

映射是定义文档及其包含的字段的存储和索引方式的过程。

每个文档都是字段的集合,每个字段都有自己的 数据类型。映射数据时,您将创建一个映射定义,其中包含与文档相关的字段列表。映射定义还包括元数据字段,例如该 _source字段,用于自定义如何处理文档的关联元数据。

使用动态映射显式映射来定义数据。每种方法都会根据您在数据旅途中的位置提供不同的好处。例如,将字段显式映射到您不想使用默认值的位置,或者获得对创建哪些字段的更大控制权。然后,您可以允许Elasticsearch动态添加其他字段。

1. 创建一个索引并且指定映射

PUT /my-index-000001
{
  "mappings": {
    "properties": {
      "age":    { "type": "integer" },  
      "email":  { "type": "keyword"  }, 
      "name":   { "type": "text"  }     
    }
  }
}

2. 在索引中添加映射

PUT /my-index-000001/_mapping
{
  "properties": {
    "addr": { "type": "keyword" }
  }
}

3. 更新映射

不能更新映射。

4. 数据迁移

//先创建出new_twitter的正确映射
//然后使用如下方式进行数据迁移
POST _reindex [固定写法]
{
    "source":{
        "index": "twitter",
        "type": "tweet" //如果有类型需加上
    },
    "dest":{
        "index": "new_twitter"
    }
}