Elasticsearch入门(1)

作者: iszhenyu | 来源:发表于2017-04-09 12:46 被阅读242次

    很多东西在工作中一直使用,但是从来没有认真总结过,遇到问题了就上网翻翻文档,工作中的问题是解决了,但是回过头去看,又好像什么都不懂,只是对经常使用的知识比较熟悉而已。这也是这篇文章产生的原因,希望通过这种方式,让自己的知识更加系统化。好了,下面就来说说ElasticSearch,这篇文章偏入门些,如果您已经对ElasticSearch非常熟悉了,当然也可以再浏览下,如果你还从来没接触过,希望这篇文章可以帮助到你。

    我们下面的讲解与实例都是基于5.2版本的,由于ElasticSearch之前的版本跟目前这个版本有一定的差别,所以如果当你对照例子发现无法运行时,那么最可能的原因就是版本的问题了。

    Elasticsearch是一个基于Lucene的开源搜索引擎,而Lucene本身是非常复杂的,要想直接使用Lucene并不是太容易。Elasticsearch的出现就是希望通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。

    ES的安装

    ES的安装是非常简单的,唯一需要我们配置的就是java环境,5.2的版本需要java8的支持,所以首先确保本地已经安装了java8或以上版本。接下来下载对应的二进制包,如果是mac或linux系统可以直接通过curl来下载

    curl -L -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.2.2.tar.gz
    

    对下载好的压缩包进行解压处理

    tar -xvf elasticsearch-5.2.2.tar.gz
    

    然后进入到解压后的elasticsearch-5.2.2/bin目录中,直接运行elasticsearch

    bin ./elasticsearch
    

    之后,新打开一个终端窗口,执行如下的命令:

    curl 'http://localhost:9200/?pretty'
    

    如果启动成功,我们会看到类似下面的响应信息:

    {
      "name" : "EF-dAP-",
      "cluster_name" : "elasticsearch",
      "cluster_uuid" : "4KsT9m6iRfqUfafnsklDcw",
      "version" : {
        "number" : "5.2.2",
        "build_hash" : "f9d9b74",
        "build_date" : "2017-02-24T17:26:45.835Z",
        "build_snapshot" : false,
        "lucene_version" : "6.4.1"
      },
      "tagline" : "You Know, for Search"
    }
    

    ES的几个概念

    在ES中,数据都是按照JSON格式存储的,比如下面的例子

    "email": "lisi@qq.com",
    "first_name": "li",
    "last_name": "si",
    "info": {
        "age": 25,
        "interests": [ "dolphins", "whales" ]
    },
    "join_date": "2017/04/06"
    

    它描述了一个user对象,同时,在ES中它也代表了一个文档。ES在对这个文档进行存储的同时,还会对文档中的内容进行倒排索引,以便于后续的查找、过滤、排序等操作。

    在关系型数据库中,我们熟悉的是databasetablerowcolumn等概念,同样,在ES中也存在着类似的定义。

    在ES中,索引(index)指的是具有相同属性的文档的集合,每个索引(index)包含多个类型(type),每个类型又包含多个文档(document),每个文档包含了多个字段(field)。如果跟关系型数据库的结构对照的话,大致可以如下表示:

    Elasticsearch 关系型数据库
    Index Database
    Type Table
    Document Row
    Field Column

    在ES中,索引是一个非常重要的概念,不同的场景下代表了不同的含义。这里有必要对在ES中使用的索引一词做一下澄清。

    传统的关系型数据库中,索引代表对数据库中的一列或多列的值进行排序的一种存储结构,利用索引可以快速获得所需的内容。

    而在ES中,索引作为名词来讲表示的是一个存储了相关文档的集合,可以对比于关系型数据库中的database。当我们在ES中保存数据时,也称为对其进行索引处理,这里按动词理解,可以对比于关系型数据库中的insert操作。

    Elasticsearch能够对全文本进行快速的搜索,得益于其实用的一种数据结构:倒排索引(Inverted Index)。在倒排索引中,包含一个在所有文档中出现的字词的列表,其中,每一个字词又对应一个列表,这个列表的内容就是所有包含这个字词的文档。当搜索时,首先会对我们搜索的内容进行分词处理,然后检查每个分好的词对应哪些文档,最后汇总给我们结果。

    ES常用操作

    ES提供了非常丰富和强大的REST API,通过这些API我们可以检查集群、节点和索引的健康情况,并对它们进行管理,可以在索引上对数据进行增删改查,更可以执行类似分页、排序、过滤、聚合等这样的高级查询操作。

    对集群、节点和索引的操作

    • 查看集群健康状态
    curl -XGET 'localhost:9200/_cat/health?v&pretty'
    

    在返回的结果中,包含一个status字段,它的取值有三种,分别是greenyellowredgreen意味着一切正常,yellow意味着数据是可用的,但是一些备份数据还没准备好,最后red意味某些数据是不可用的,尽管如此,但部分功能还是可用的,只不过你需要尽快去处理。

    • 查看集群下的节点信息
    curl -XGET 'localhost:9200/_cat/nodes?v&pretty'
    
    • 查看当前集群都有哪些索引
    curl -XGET 'localhost:9200/_cat/indices?v&pretty'
    
    • 新建一个名为customer的索引
    curl -XPUT 'localhost:9200/customer?pretty&pretty'
    
    • 删除名为customer的索引
    curl -XDELETE 'localhost:9200/customer?pretty&pretty'
    
    • 创建别名
    curl -XPUT 'localhost:9200/xx_questions_v1/_alias/xx_questions'
    
    • 通过别名查询所指向的索引
    curl -XGET 'localhost:9200/_alias/xx_questions?pretty'
    // or
    curl -XGET 'localhost:9200/_alias/xx_questions*?pretty'
    
    • 查询指向该索引下的所有别名
    curl -XGET 'localhost:9200/xx_questions_v1/_alias?pretty'
    
    • 删除别名
    curl -XDELETE 'localhost:9200/xx_questions_v1/_alias/xx_questions'
    
    • 删除别名的同时添加别名到新的索引
    curl -XPOST 'http://localhost:9200/_aliases' -d '
    {
        "actions" : [
            { "remove" : { "index" : "dm_v1", "alias" : "dm" } },
            { "add" : { "index" : "dm_v2", "alias" : "dm" } }
        ]
    }'
    
    • 修改索引的设置
    curl -XPUT 'http://localhost:9200/task_es/_settings' -H 'Content-Type:appliation' -d '{
        "index": {
            "refresh_interval": "30s",
            "number_of_replicas": 1
        }
    }'
    
    • 创建mapping
    curl -XPOST 'http://localhost:9200/{index}/_mapping?pretty=true' -H 'Content-Type:application/json' -d '{
        // mapping
    }'
    

    索引上的增删改查

    首先,在customer索引上新增一个文档

    curl -XPUT 'localhost:9200/customer/external/1?pretty&pretty' -H 'Content-Type: application/json' -d'
    {
      "first_name": "zhang", "last_name":"si"
    }
    '
    

    上面的语句执行完毕后,会在customer索引中的external类型中新加入一个ID为1的文档。我们可以通过ID来访问这个新加入的文档:

    curl -XGET 'localhost:9200/customer/external/1?pretty&pretty'
    

    它的结果应该像下面这样,除了一个found字段,就没啥特别的了

    {
      "_index" : "customer",
      "_type" : "external",
      "_id" : "1",
      "_version" : 1,
      "found" : true,
      "_source" : { "first_name": "zhang", "last_name": "si"}
    }
    

    这里要说明的是,Elasticsearch中对数据进行操作后,并不是立即就能够搜索的,这中间会有大概1秒钟的延迟。

    现在,假如我们想将这个ID为1的文档替换成其他的文档,比如换成名字为lisi的文档,则只需要再执行一次上面的put操作即可,ID还是指定为1:

    curl -XPUT 'localhost:9200/customer/external/1?pretty&pretty' -H 'Content-Type: application/json' -d'
    {
      "first_name": "li", "last_name":"si"
    }
    '
    

    再次获取ID为1的文档,我们发现名称已经变成了lisi。假如说我们在执行替换的时候指定的ID不是1,比如是2,会怎样呢?

    curl -XPUT 'localhost:9200/customer/external/2?pretty&pretty' -H 'Content-Type: application/json' -d'
    {
      "first_name": "wang", "last_name": "wu"
    }
    '
    

    这句话执行的结果就是索引了一个新的文档,新文档的ID是2。

    可以看到,ES跟传统关系型数据库是不同的,在传统关系型数据库中,如果库中已经有一个ID是1的数据(这里ID作为主键)则再执行插入为1的操作会报错。而在ES中,通过PUT可以来进行createupdate这两种操作,我们可以这样理解:当ES中已经存在特定的ID时,会执行更新操作,当ES中没有这个ID时会执行插入操作。

    在ES内部,其实并不是真正的去更新文档,而是先删除旧的文档,再重新索引这个新的文档。所以,也就不难理解为什么上面的两个PUT操作会有不同的效果了。

    除了索引文档的时候可以指定ID外,也可以不指定,如果不指定ID,ES会生成一个随机的ID,同时,必须使用POST方法来索引一个文档:

    curl -XPOST 'localhost:9200/customer/external?pretty&pretty' -H 'Content-Type: application/json' -d'
    {
      "first_name": "zhao", "last_name": "liu"
    }
    '
    

    对于更新操作,有的时候我们并不想更新整个文档,而只是想更新文档中的某个字段,怎么操作呢?我们还以上面为例,假如只想改变first_name字段,名字改成zhang lisi:

    curl -XPOST 'localhost:9200/customer/external/1/_update?pretty&pretty' -H 'Content-Type: application/json' -d'
    {
      "doc": { "first_name": "zhang" }
    }
    '
    

    与上面替换整个文档不同的是,我们这里使用的是POST操作,同时在url中指定了是_update,并且,将要更新的内容嵌套在了doc字段中。通过这个操作,我们不但可以更新已有的字段,也可以新增字段,比如,下面的操作会新增一个age字段:

    curl -XPOST 'localhost:9200/customer/external/1/_update?pretty&pretty' -H 'Content-Type: application/json' -d'
    {
      "doc": { "first_name": "zhang", "age": 25 }
    }
    '
    

    根据RESTful API规范,我们不难推断出来,删除一个文档只要使用DELETE句可以了:

    curl -XDELETE 'localhost:9200/customer/external/2?pretty&pretty'
    

    我们上面的操作都是基于单个文档的,ES同样提供了批量操作的接口。使用批量操作也很简单,首先在URL上通过_bulk告诉ES我们使用的是批量操作,其次,对于每个数据,我们还要告诉ES是什么类型的操作,比如下面的例子:

    curl -XPOST 'localhost:9200/customer/external/_bulk?pretty&pretty' -H 'Content-Type: application/json' -d'
    {"index":{"_id":"1"}}
    {"first_name": "zhang", "last_name": "san"}
    {"index":{"_id":"2"}}
    {"first_name": "li", "last_name": "si"}
    '
    

    {"index":{"_id":"1"}}告诉ES是要新索引一个文档,文档的ID是1,紧跟着的{"first_name": "zhang", "last_name": "san"}是这个ID为1的文档的内容,同理,我们也可以在一次批处理中同时包含更新和删除操作:

    curl -XPOST 'localhost:9200/customer/external/_bulk?pretty&pretty' -H 'Content-Type: application/json' -d'
    {"update":{"_id":"1"}}
    {"doc": { "last_name": "san si wu" } }
    {"delete":{"_id":"2"}}
    '
    

    上面的操作会首先更新ID为1的文档的last_name字段,然后删除ID为2的文档。

    在入门(1)中,主要就是介绍一下ES的基本的概念和一些基本的操作,在入门(2)中会继续介绍ES中的高级查询。


    这样学机器学习

    相关文章

      网友评论

        本文标题:Elasticsearch入门(1)

        本文链接:https://www.haomeiwen.com/subject/wzddattx.html