ElasticSearch 入门教程

一、docker 搭建elasticsearch+kibana

Elasticsearch 是个开源分布式搜索引擎,它的特点有:分布式,零配置,自动发现,索引自动分片,索引副本机制,restful风格接口,多数据源,自动搜索负载等。

kibana 是一个开源和免费的工具,它可以为 ElasticSearch 提供的日志分析友好的 Web 界面,可以帮助您汇总、分析和搜索重要数据日志。

(1)es:

docker pull elasticsearch:7.1.1
docker network create ek
docker run -d --name elasticsearch --net ek -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.1.1

访问http://localhost:9200/ ,可以看到es集群信息:

{
  "name" : "0c784878759f",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "6g4oTiDSSxWaOG9-yApTsg",
  "version" : {
    "number" : "7.1.1",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "7a013de",
    "build_date" : "2019-05-23T14:04:00.380842Z",
    "build_snapshot" : false,
    "lucene_version" : "8.0.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

(2)kibana:

docker pull kibana:7.1.1

docker run -d --name kibana --net ek -p 5601:5601 kibana:7.1.1

 

二、基本概念

(1)Node 与 Cluster

Elastic 本质上是一个分布式数据库,允许多台服务器协同工作,每台服务器可以运行多个 Elastic 实例。

单个 Elastic 实例称为一个节点(node)。一组节点构成一个集群(cluster)。

(2)Index(索引)

索引是含有相同属性的文档的集合。

 

Elastic 会索引所有字段,经过处理后写入一个反向索引(Inverted Index)。查找数据的时候,直接查找该索引。

所以,Elastic 数据管理的顶层单位就叫做 Index(索引)。它是单个数据库的同义词。每个 Index (即数据库)的名字必须是小写。

下面的命令可以查看当前节点的所有 Index。

curl http://localhost:9200/_cat/indices?

 

也可以在kibana中执行 GET /_cat/indeices?v 查看所有的index:

 

(3)Document

Index 里面单条的记录称为 Document(文档)。许多条 Document 构成了一个 Index。

Document 使用 JSON 格式表示,下面是一个例子。

{
  "user": "张三",
  "title": "工程师",
  "desc": "数据库管理"
}

同一个 Index 里面的 Document,不要求有相同的结构(scheme),但是最好保持相同,这样有利于提高搜索效率。

(4)分片和备份

在es集群中,每个索引都有多个分片,每个分片都是一个Lucene索引。

将较大的索引分成多个分片可以加快搜索速度,并且可以进行水平的扩展和拆分以及分布式的操作。

分片数量只能在创建索引的时候指定。

备份是指一个节点拷贝了另一个节点的分片。备份可以实现数据的高可用。


三、基本操作

1.创建索引

(1)可以通过postman发送put请求  http://localhost:9200/movies,创建一条名为movies的索引。

(2)也可以在kibana中执行如下命令创建movies索引:

PUT /movies

同时还可以配置索引的参数,例如分片个数和备份个数,例如:

PUT /movies
{
    "settings" : {
        "index" : {
            "number_of_shards" : 3,
            "number_of_replicas" : 2
        }
    }
}

此外,如果插入数据时,索引不存在,es会自动创建索引,例如这里创建一个id为1的数据,如果movies不存在,会先创建movies索引:

PUT /movies/_create/1
{
    "title": "The Godfather",
    "director": "Francis Ford Coppola",
    "year": 1972
}

索引的名称必须是小写的,不可重名。

 

2.更新索引

(1)修改备份数

PUT /movies/_settings
{
    "index" : {
        "number_of_replicas" : 2
    }
}

(2)设置回默认值,用null

PUT /movies/_settings
{
    "index" : {
        "number_of_replicas" : null
    }
}

3.查询文档

(1)查询索引中的所有文档

GET /movies/_search

(2)根据id查询文档

GET /movies/_doc/5

4.向索引中插入文档

(1)插入单挑

使用PUT请求,_create路径

PUT /movies/_create/5
{
    "title": "The Godfather",
    "director": "Francis Ford Coppola",
    "year": 1975
}

在索引movies中插入一条id为5的数据。

(2)插入多条

使用/_bulk路径

PUT /store/_bulk

{ "index": {"_id": 1}}

{ "price": 10, "productID": "SD1002136"}

{ "index": {"_id": 2}}

{ "price": 20, "productID": "SD2678421"}

{ "index": {"_id": 3}}

{ "price": 30, "productID": "SD8897573"}

{ "index": {"_id": 4}}

{ "price": 40, "productID": "SD4535233"}

 

5.从索引中删除文档

(1)使用DELETE请求,携带要删除的文档id

DELETE /movies/_doc/5

 

 

(2)删除索引下的全部数据,但不删除索引

POST /movies/_delete_by_query?pretty
{
  "query": {
    "match_all": {}
  }
}

6.更新索引中的文档

(1)整体更新

使用PUT请求,携带要修改的文档id

PUT /movies/_doc/5
{
    "title": "The Godfather",
    "director": "Francis Ford Coppola",
    "year": 1970
}

(2)局部更新

注意这里,局部更新使用POST请求,并且请求路径是/{index}/_update/{_id},而整体更新使用PUT请求。

而且要注意局部更新的数据是包裹在doc这个json对象中:

POST /movies/_update/5/
{
  "doc" : {
    "year": 1979
  }
}

(3)更新可能不存的文档

在局部更新操作中,如果遇到了不存在的文档,会出现失败的操作,例如:

但是,有时候也需要对不存在的文档进行更新【创建】,可以使用关键字:upsert 。然后如果文档存在就直接更新,如果文档不存在,那么就创建这个文档。

注意这里doc里面传入的是需要局部更新的字段和数据,而upsert里面是文档不存在的情况下插入的文档数据:

POST /movies/_update/11/
{
  "doc" : {
    "year": 1979
  },

  
  "upsert" : {
    "title": "The Godfather",
    "director": "Francis Ford Coppola",
    "year": 1975
  }
}

7.删除索引

使用DELETE请求

DELETE /movies

8.判断索引是否存在

HEAD /movies

 


四、高级查询

先插入6条测试数据:

PUT /movies/_create/1

{

    "title": "The Godfather",

    "director": "Francis Ford Coppola",

    "year": 1972,

    "genres": ["Crime", "Drama"]

}



PUT /movies/_create/2

{

    "title": "Lawrence of Arabia",

    "director": "David Lean",

    "year": 1962,

    "genres": ["Adventure", "Biography", "Drama"]

}



PUT /movies/_create/3

{

    "title": "To Kill a Mockingbird",

    "director": "Robert Mulligan",

    "year": 1962,

    "genres": ["Crime", "Drama", "Mystery"]

}



PUT /movies/_create/4

{

    "title": "Apocalypse Now",

    "director": "Francis Ford Coppola",

    "year": 1979,

    "genres": ["Drama", "War"]

}



PUT /movies/_create/5

{

    "title": "Kill Bill: Vol. 1",

    "director": "Quentin Tarantino",

    "year": 2003,

    "genres": ["Action", "Crime", "Thriller"]

}



PUT /movies/_create/6

{

    "title": "The Assassination of Jesse James by the Coward Robert Ford",

    "director": "Andrew Dominik",

    "year": 2007,

    "genres": ["Biography", "Crime", "Drama"]

}



PUT /movies/_create/7

{

    "title": "ABC",

    "director": "Bill",

    "year": 2007,

    "genres": ["Biography", "Crime", "Drama"]

}

(1)搜索请求正文和ElasticSearch查询DSL

如果只是发送一个GET /movies/_search请求,我们会得到所有的电影信息。为了创建更有用的搜索请求,还需要向请求正文中提供查询。 

请求正文是一个JSON对象,除了其它属性以外,它还要包含一个名称为“query”的属性,这就可使用ElasticSearch的查询DSL。例如这里的match_all得出的结果就是movies下的所有文档:

GET /movies/_search
{
    "query": {
      "match_all": {}
    }
}

(2)基本自由文本搜索

查询DSL具有一长列不同类型的查询可以使用。 对于“普通”自由文本搜索,最有可能想使用一个名称为“查询字符串查询”。

查询字符串查询是一个高级查询,有很多不同的选项,ElasticSearch将解析和转换为更简单的查询树。如果忽略了所有的可选参数,并且只需要给它一个字符串用于搜索,它可以很容易使用。

现在尝试在两部电影的标题中搜索有“kill”这个词的电影信息:

GET /movies/_search
{
    "query": {
      "query_string": {
            "query": "kill"
        }
    }
}

注意这里的每个文档查询结果里面都有一个_score字段,这个分数值计算的是一个文档相对于其他文档和查询子句的匹配程度。

 

(3)指定搜索的字段

在前面的例子中,使用了一个非常简单的查询,一个只有一个属性“query”的查询字符串查询。 如前所述,查询字符串查询有一些可以指定设置,如果不使用,它将会使用默认的设置值。

这样的设置称为“fields”,可用于指定要搜索的字段列表。如果不使用“fields”字段,ElasticSearch查询将默认自动生成的名为“_all”的特殊字段,来基于所有文档中的各个字段匹配搜索。

为了做到这一点,修改以前的搜索请求正文,以便查询字符串查询有一个fields属性用来要搜索的字段数组,这里查询标题中含有Bill的电影文档:

GET /movies/_search
{
    "query": {
      "query_string": {
            "query": "Bill",
            "fields": ["title"]
        }
    }
}

fields中传入多个字段,则可以查找出"title"和"director"字段中含有"Bill"的文档:

GET /movies/_search
{
    "query": {
      "query_string": {
            "query": "Bill",
            "fields": ["title","director"]
        }
    }
}

(4)过滤

过滤查询filter已被弃用,并在ES 5.0中删除。新版本必须使用bool / must / filter查询。

例如这里查询标题中含有kill,并且year是1962的文档:

GET /movies/_search

{

  "query": {

    "bool": {

      "must": [

        { "match": { "title":   "kill"  }}

      ],

      "filter": [

        { "term":  { "year": 1962 }}

      ]

    }

  }

}

还可以使用范围查询range,查询year大于等于2000并且小于2100的文档:

GET /movies/_search

{

  "query": {

    "bool": {

      "must": [

        { "match": { "title":   "kill"  }}

      ],

      "filter": [

        {"range" : { "year" : {

            "gte" : 2000,

            "lt" : 2100

            }

          }

        }

      ]

    }

  }

}


 

五、Mapping映射

Mapping 类似于数据库中的表结构定义 schema,它有以下几个作用:

  • 定义索引中的字段的名称

  • 定义字段的数据类型,比如字符串、数字、布尔

  • 字段,倒排索引的相关配置,比如设置某个字段为不被索引、记录 position 等

在 ES 早期版本,一个索引下是可以有多个 Type ,从 7.0 开始,一个索引只有一个 Type,也可以说一个 Type 有一个 Mapping 定义。

 

在创建一个索引的时候,可以对 dynamic 进行设置,可以设成 false、true 或者 strict。

如果是新增加的字段,根据 Dynamic 的设置分为以下三种状况:

  • 当 Dynamic 设置为 true 时,一旦有新增字段的文档写入,Mapping 也同时被更新。
  • 当 Dynamic 设置为 false 时,索引的 Mapping 是不会被更新的,新增字段的数据无法被索引,也就是无法被搜索,但是信息会出现在 _source 中。
  • 当 Dynamic 设置为 strict 时,文档写入会失败。

另外一种是字段已经存在,这种情况下,ES 是不允许修改字段的类型的,因为 ES 是根据 Lucene 实现的倒排索引,一旦生成后就不允许修改,如果希望改变字段类型,必须使用 Reindex API 重建索引。

不能修改的原因是如果修改了字段的数据类型,会导致已被索引的无法被搜索,但是如果是增加新的字段,就不会有这样的影响。

 

另外还有 index 参数,用来控制当前字段是否被索引,默认为 true,如果设为 false,则该字段不可被搜索。

核心类型可以划分为字符串类型、数字类型、日期类型、布尔类型、基于 BASE64 的二进制类型、范围类型。

 

在 ES 7.x 有两种字符串类型:text 和 keyword。text类型和keyword类型的区别:

  • text 类型适用于需要被全文检索的字段,例如新闻正文、邮件内容等比较长的文字,text 类型会被 Lucene 分词器(Analyzer)处理为一个个词项,并使用 Lucene 倒排索引存储,text 字段不能被用于排序,如果需要使用该类型的字段只需要在定义映射时指定 JSON 中对应字段的 type 为 text。

  • keyword 适合简短、结构化字符串,例如主机名、姓名、商品名称等,可以用于过滤、排序、聚合检索,也可以用于精确查询。

 

(1)创建索引的同时添加mapping:

PUT /movies
{
    "mappings": {
        "properties": {
            "title": {
                "type": "text",
                "store": true,
                "index": true,
                "analyzer": "standard"
            },
            "year": {
                "type": "long",
                "store": true,
                "index": true,
                "analyzer": "standard"
            }
        }
    }
}

(2)向索引中新增字段时添加mapping:

PUT /movies/_mapping
{

  "properties": {
    "online": {
      "type": "boolean",
      "index": false
    }
  }
}

(3)不推荐修改已有字段的mapping

官方文档:

Update the mapping of a fieldedit

Except for supported mapping parameters, you can’t change the mapping or field type of an existing field. Changing an existing field could invalidate data that’s already indexed.

If you need to change the mapping of a field in a data stream’s backing indices, see Change mappings and settings for a data stream.

If you need to change the mapping of a field in other indices, create a new index with the correct mapping and reindex your data into that index.

Renaming a field would invalidate data already indexed under the old field name. Instead, add an alias field to create an alternate field name.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值