Elasticsearch基础入门

本文以 Elasticsearch 5.6.2为例。 最新(截止到2018-09-23)的 Elasticsearch 是 6.4.1。5.x系列和6.x系列虽然有些区别,但基本用法是一样的。 官方文档: https://www.elastic.co/guide/en/elasticsearch/reference/5.6/ 安装 安装比较简单。分两步: 配置JDK环境 安装Elasticsearch Elasticsearch 依赖 JDK环境,需要系统先下载安装 JDK 并配置 JAVA_HOME 环境变量。JDK 版本推荐:1.8.0系列。地址:https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 安装JDk Linux: $ yum install -y java-1.8.0-openjdk 配置环境变量,需要修改/etc/profile, 增加: JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.181-3.b13.el6_10.x86_64 PATH=$JAVA_HOME/bin:$PATH CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar JAVACMD=/usr/bin/java export JAVA_HOME JAVACMD CLASSPATH PATH 然后使之生效: source /etc/profile Windows: 安装包地址: http://download.oracle.com/otn-pub/java/jdk/8u191-b12/2787e4a523244c269598db4e85c51e0c/jdk-8u191-windows-x64.exe 下载并配置JDK环境变量 JAVA_HOME=C:\Program Files\Java\jdk1.8.0_101 CLASSPATH=.;%JAVA_HOME%\lib;.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar; 安装Elasticsearch Elasticsearch 安装只需要下载二进制压缩包包,解压即可使用。需要特别注意的是版本号,如果还要安装Kibana及插件,需要注意选用一样的版本号。 安装包下载:https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.6.2.tar.gz 这个页面有 Elasticsearch 所有版本的下载:https://www.elastic.co/downloads/past-releases 下载后解压到指定目录,进入到 bin 目录,就可以运行 Elasticsearch 了: Linux: ./elasticsearch Windows: elasticsearch.bat 注: Linux/Mac环境不能使用 root 用户运行。 基础入门 我们可以使用curl或者kibana提供的Dev Tools进行API测试。 例如: curl方式: curl 'localhost:9200/_cat/health?format=json' [{"epoch":"1537689647","timestamp":"16:00:47","cluster":"elasticsearch","status":"yellow","node.total":"1","node.data":"1","shards":"11","pri":"11","relo":"0","init":"0","unassign":"11","pending_tasks":"0","max_task_wait_time":"-","active_shards_percent":"50.0%"}] Dev Tools: GET /_cat/health?format=json 个人比较喜欢Kibana提供的Dev Tools,非常方便。 查看_cat命令: GET _cat =^.^= /_cat/allocation /_cat/shards /_cat/shards/{index} /_cat/master /_cat/nodes /_cat/tasks /_cat/indices /_cat/indices/{index} /_cat/segments /_cat/segments/{index} /_cat/count /_cat/count/{index} /_cat/recovery /_cat/recovery/{index} /_cat/health /_cat/pending_tasks /_cat/aliases /_cat/aliases/{alias} /_cat/thread_pool /_cat/thread_pool/{thread_pools} /_cat/plugins /_cat/fielddata /_cat/fielddata/{fields} /_cat/nodeattrs /_cat/repositories /_cat/snapshots/{repository} /_cat/templates 以下测试均在Dev Tools执行。 节点操作 查看健康状态 GET /_cat/health?format=json 结果: [ { "epoch": "1537689915", "timestamp": "16:05:15", "cluster": "elasticsearch", "status": "yellow", "node.total": "1", "node.data": "1", "shards": "11", "pri": "11", "relo": "0", "init": "0", "unassign": "11", "pending_tasks": "0", "max_task_wait_time": "-", "active_shards_percent": "50.0%" } ] 健康状态有3种: Green - 正常(集群功能齐全) Yellow - 所有数据均可用,但尚未分配一些副本(群集功能齐全) Red - 某些数据由于某种原因不可用(群集部分功能可用) 注意:当群集为红色时,它将继续提供来自可用分片的搜索请求,但您可能需要尽快修复它,因为存在未分配的分片。 查看节点 GET /_cat/nodes?format=json 索引 查看所有index GET /_cat/indices?format=json 结果: [ { "health": "yellow", "status": "open", "index": "filebeat-2018.09.23", "uuid": "bwWVhUkBTIe46h9QJfmZHw", "pri": "5", "rep": "1", "docs.count": "4231", "docs.deleted": "0", "store.size": "2.5mb", "pri.store.size": "2.5mb" }, { "health": "yellow", "status": "open", "index": ".kibana", "uuid": "tnWbNLSMT7273UEh6RfcBg", "pri": "1", "rep": "1", "docs.count": "4", "docs.deleted": "0", "store.size": "23.9kb", "pri.store.size": "23.9kb" } ] 创建index PUT /customer 删除index DELETE /customer 查询指定 Index 的 mapping GET /customer/_mapping 注:ElasticSearch里面有 index 和 type 的概念:index称为索引,type为文档类型,一个index下面有多个type,每个type的字段可以不一样。这类似于关系型数据库的 database 和 table 的概念。但是,ES中不同type下名称相同的filed最终在Lucene中的处理方式是一样的。所以后来ElasticSearch团队想去掉type,于是在6.x版本为了向下兼容,一个index只允许有一个type。预计7.x版本彻底去掉type。参考:https://www.elastic.co/guide/en/elasticsearch/reference/current/removal-of-types.html 所以,实际使用中建议一个index里面仅有一个type,名称可以和index一致,或者使用固定的doc。 增删改查 按ID新增数据 type为doc: PUT /customer/doc/1 { "name": "John Doe" } PUT /customer/doc/2 { "name": "yujc", "age":22 } 如果index不存在,直接新增数据也会同时创建index。 同时,该操作也能修改数据: PUT /customer/doc/2 { "name": "yujc", "age":23 } age字段会被修改,而且_version会被修改为2: { "_index": "customer", "_type": "doc", "_id": "1", "_version": 2, "result": "updated", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "created": false } 按ID查询数据 GET /customer/doc/1 结果: { "_index": "customer", "_type": "doc", "_id": "1", "_version": 2, "found": true, "_source": { "name": "John Doe" } } 直接新增数据 我们也可以不指定文档ID从而直接新增数据: POST /customer/doc { "name": "yujc", "age":23 } 注意这里使用的动作是POST。PUT新增数据必须指定文档ID。 更新数据 我们使用下面两种方式均能更新已有数据: PUT /customer/doc/1 { "name": "yujc2", "age":22 } POST /customer/doc/1 { "name": "yujc2", "age":22 } 以上操作均会覆盖现有数据。 如果只是想更新指定字段,必须使用POST加参数的形式: POST /customer/doc/1/_update { "doc":{"name": "yujc"} } 其中_update表示更新。json里doc必须有,否则会报错。 增加字段: POST /customer/doc/1/_update { "doc":{"year": 2018} } 就会在已有的数据基础上增加一个year字段,不会覆盖已有数据: GET /customer/doc/1 结果: { "_index": "customer", "_type": "doc", "_id": "1", "_version": 16, "found": true, "_source": { "name": "yujc", "age": 22, "year": 2018 } } 也可以使用简单脚本执行更新。此示例使用脚本将年龄增加5: POST /customer/doc/1/_update { "script":"ctx._source.age+=5" } 结果: { "_index": "customer", "_type": "doc", "_id": "1", "_version": 17, "found": true, "_source": { "name": "yujc", "age": 27, "year": 2018 } } 按ID删除数据 DELETE /customer/doc/1 批量 新增 POST /customer/doc/_bulk {"index":{"_id":"1"}} {"name": "John Doe" } {"index":{"_id":"2"}} {"name": "Jane Doe" } 该操作会新增2条记录,而不是4条。查询数据: GET /customer/doc/2 结果: { "_index": "customer", "_type": "doc", "_id": "2", "_version": 2, "found": true, "_source": { "name": "Jane Doe" } } 更新、删除 POST /customer/doc/_bulk {"update":{"_id":"1"}} {"doc": { "name": "John Doe becomes Jane Doe" } } {"delete":{"_id":"2"}} 该操作会更新ID为1的文档,删除ID为2的文档。 注意:批量操作如果某条失败了,并不影响下一条继续执行。 防盗版声明:本文系原创文章,发布于公众号飞鸿影的博客(fhyblog)及博客园,转载需作者同意。 全文检索 经过前面的基础入门,我们对ES的基本操作也会了。现在来学习ES最强大的部分:全文检索。 准备工作 批量导入数据 先需要准备点数据,然后导入: wget https://raw.githubusercontent.com/elastic/elasticsearch/master/docs/src/test/resources/accounts.json curl -H "Content-Type: application/json" -XPOST "localhost:9200/bank/account/_bulk&refresh" --data-binary "@accounts.json" 这样我们就导入了1000条数据到ES。index是bank。我们可以查看现在有哪些index: curl "localhost:9200/_cat/indices?format=json&pretty" 结果: [ { "health" : "yellow", "status" : "open", "index" : "bank", "uuid" : "IhyOzz3WTFuO5TNgPJUZsw", "pri" : "5", "rep" : "1", "docs.count" : "1000", "docs.deleted" : "0", "store.size" : "640.3kb", "pri.store.size" : "640.3kb" }, { "health" : "yellow", "status" : "open", "index" : "customer", "uuid" : "f_nzBLypSUK2SVjL2AoKxQ", "pri" : "5", "rep" : "1", "docs.count" : "9", "docs.deleted" : "0", "store.size" : "31kb", "pri.store.size" : "31kb" }, { "health" : "yellow", "status" : "open", "index" : ".kibana", "uuid" : "tnWbNLSMT7273UEh6RfcBg", "pri" : "1", "rep" : "1", "docs.count" : "5", "docs.deleted" : "0", "store.size" : "29.4kb", "pri.store.size" : "29.4kb" } ] 使用kibana可视化数据 该小节是可选的,如果不感兴趣,可以跳过。 该小节要求你已经搭建好了ElasticSearch + Kibana。 打开kibana web地址:http://127.0.0.1:5601,依次打开:Management -> Kibana -> Index Patterns ,选择Create Index Pattern: a. Index pattern 输入:bank ; b. 点击Create。 然后打开Discover,选择 bank 就能看到刚才导入的数据了。 我们在可视化界面里检索数据: 是不是很酷! 接下来我们使用API来实现检索。 关键字检索 模糊检索 GET /bank/_search?q="Virginia"&pretty 解释:检索关键字为"Virginia"的结果。结果示例: { "took": 4, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 2, "max_score": 4.631368, "hits": [ { "_index": "bank", "_type": "account", "_id": "298", "_score": 4.631368, "_source": { "account_number": 298, "balance": 34334, "firstname": "Bullock", "lastname": "Marsh", "age": 20, "gender": "M", "address": "589 Virginia Place", "employer": "Renovize", "email": "bullockmarsh@renovize.com", "city": "Coinjock", "state": "UT" } }, { "_index": "bank", "_type": "account", "_id": "25", "_score": 4.6146765, "_source": { "account_number": 25, "balance": 40540, "firstname": "Virginia", "lastname": "Ayala", "age": 39, "gender": "F", "address": "171 Putnam Avenue", "employer": "Filodyne", "email": "virginiaayala@filodyne.com", "city": "Nicholson", "state": "PA" } } ] } } 返回字段含义: took – Elasticsearch执行搜索的时间(以毫秒为单位) timed_out – 搜索是否超时 _shards – 搜索了多少个分片,以及搜索成功/失败分片的计数 hits – 搜索结果,是个对象 hits.total – 符合我们搜索条件的文档总数 hits.hits – 实际的搜索结果数组(默认为前10个文档) hits.sort - 对结果进行排序(如果按score排序则没有该字段) hits._score、max_score - 暂时忽略这些字段 GET /bank/_search?q=*&sort=account_number:asc&pretty 解释:所有结果通过account_number字段升序排列。默认只返回前10条。 下面的查询与上面的含义一致: GET /bank/_search { "query": { "multi_match" : { "query" : "Virginia", "fields" : ["_all"] } } } GET /bank/_search { "query": { "match_all": {} }, "sort": [ { "account_number": "asc" } ] } 通常我们会采用传JSON方式查询。Elasticsearch提供了一种JSON样式的特定于域的语言,可用于执行查询。这被称为查询DSL。 注意:上述的查询里面我们仅指定了index,并没有指定type,那么ES将不会区分type。如果想区分,请在URI后面追加type。示例:GET /bank/account/_search。 字段检索 再看按字段查询: GET /bank/_search { "query": { "multi_match" : { "query" : "Virginia", "fields" : ["firstname"] } } } GET /bank/_search { "query": { "match" : { "firstname" : "Virginia" } } } 上面2种查询是等效的,都是查询firstname为Virginia的结果。 不分词 默认检索都是分词的,如果我们希望精确匹配,可以这样实现: GET /bank/_search { "query": { "match" : { "address.keyword" : "171 Putnam Avenue" } } } 在字段后面加上.keyword表示不分词,使用精确匹配。大家可以测试下面2种查询结果的区别: GET /bank/_search { "query": { "match" : { "address" : "Putnam" } } } GET /bank/_search { "query": { "match" : { "address.keyword" : "Putnam" } } } 第二种将查不到任何结果。 分页 分页使用关键字from、size,分别表示偏移量、分页大小。 GET /bank/_search { "query": { "match_all": {} }, "from": 0, "size": 2 } from默认是0,size默认是10。 字段排序 字段排序关键字是sort。支持升序(asc)、降序(desc)。 GET /bank/_search { "query": { "match_all": {} }, "sort": [ { "account_number": "asc" } ], "from":0, "size":10 } 过滤字段 默认情况下,ES返回所有字段。这被称为源(_source搜索命中中的字段)。如果我们不希望返回所有字段,我们可以只请求返回源中的几个字段。 GET /bank/_search { "query": { "match_all": {} }, "_source": ["account_number", "balance"] } 通过_source关键字可以实现字段过滤。 AND查询 如果我们想同时查询符合A和B字段的结果,该怎么查呢?可以使用must关键字组合。 GET /bank/_search { "query": { "bool": { "must": [ { "match": { "address": "mill" } }, { "match": { "address": "lane" } } ] } } } GET /bank/_search { "query": { "bool": { "must": [ { "match": { "account_number":136 } }, { "match": { "address": "lane" } }, { "match": { "city": "Urie" } } ] } } } must也等价于: GET /bank/_search { "query": { "bool": { "must": [ { "match": { "address": "mill" } } ], "must": [ { "match": { "address": "lane" } } ] } } } 这种相当于先查询A再查询B,而上面的则是同时查询符合A和B,但结果是一样的,执行效率可能有差异。有知道原因的朋友可以告知。 OR查询 ES使用should关键字来实现OR查询。 GET /bank/_search { "query": { "bool": { "should": [ { "match": { "account_number":136 } }, { "match": { "address": "lane" } }, { "match": { "city": "Urie" } } ] } } } AND取反查 must_not关键字实现了既不包含A也不包含B的查询。 GET /bank/_search { "query": { "bool": { "must_not": [ { "match": { "address": "mill" } }, { "match": { "address": "lane" } } ] } } 表示 address 字段需要符合既不包含 mill 也不包含 lane。 布尔组合查询 我们可以组合 must 、should 、must_not 进行复杂的查询。 A AND NOT B GET /bank/_search { "query": { "bool": { "must": [ { "match": { "age": 40 } } ], "must_not": [ { "match": { "state": "ID" } } ] } } } 相当于SQL: select * from bank where age=40 and state!= "ID"; A AND (B OR C) GET /bank/_search { "query":{ "bool":{ "must":[ {"match":{"age":39}}, {"bool":{"should":[ {"match":{"city":"Nicholson"}}, {"match":{"city":"Yardville"}} ]} } ] } } } 相当于SQL: select * from bank where age=39 and (city="Nicholson" or city="Yardville"); 范围查询 GET /bank/_search { "query": { "bool": { "must": { "match_all": {} }, "filter": { "range": { "balance": { "gte": 20000, "lte": 30000 } } } } } } 相当于SQL: select * from bank where balance between 20000 and 30000; 聚合查询 GE
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信