> 本文最早公布于公众号极客军营,原文地址
学习ElasticSearch(后续简称ES)最好的办法就是多入手实际。在该系列教程中,我会应用“在线书店”这个小我的项目贯通每一个章节。这个我的项目的背景很简略,每本书都有ISBN、题目(title)、形容(description)、价格(price)、作者(author)、出版社(publisher)和库存(stock)七个属性,将书的信息存储在ES中,用户能够依据书的某些属性信息搜寻想要买的书。
为了能让大家对ES整体有一个直观的感触,本节我将率领大家疾速浏览ES的各项能力。你刚看到某些概念可能会一头雾水,不过没有关系,本节波及到的所有内容在后续的章节中都有具体介绍,大家对本节中呈现的概念只须要先有个意识即可。
与ElasticSearch交互
要应用ES提供的服务,首先要晓得如何给ES下达指令。ES服务器提供了一系列的RESTful API,能够通过HTTP协定将数据或指令以JSON序列化的模式发送给ES提供的API接口。
咱们都晓得,基于RESTful格调设计的网络应用应用GET、POST、PUT、DELETE四种HTTP动词对服务端资源进行操作,其中GET用于获取资源,POST用于新建资源,PUT用于更新资源,DELETE用于删除资源。
例如,通过上面的curl命令发送HTTP POST申请给ES,保留一本书的信息:
curl -X POST -H "Content-Type: application/json" -d \ '{"title": "零根底学Java", "description": "自学JAVA的入门图书", "price": 66.88}' \http://localhost:9200/book_store/_doc?pretty
该条curl命令的执行后果如下图,任何编程语言或工具都能够通过HTTP协定调用ElasticSearch提供的RESTful API接口。
如果咱们每次都通过一长串的curl命令调用ElasticSearch未免有点繁琐,Kibana为咱们提供了更不便的操作形式。
在Kibana左侧导航栏中,有一个菜单叫做Dev Tools(开发工具),菜单地位见下图:
应用Dev Tools能够让咱们以十分便当的形式操作ES,例如下图在Dev Tools中的操作与上述的curl命令完全相同——在ES中保留一本书的信息。
相比于应用curl命令, 在Kibana Dev Tools中能够省略对Content-Type的申明、ES服务器的IP地址和监听端口。因为这些信息Kibana都晓得,会主动帮咱们增加上,就不必咱们额定明确指定了。此外在Kibana中输出的命令格局比拟好看,点击箭头(Click to send request)就能够间接向ES发送命令,并在其右侧显示Response后果,应用起来十分不便。
前面所有的示例代码都是在Kibana中应用的,即都不须要明确指定HTTP Header信息和服务器IP地址。
基本概念
在介绍其它内容之前,咱们先来认真看看ES返回的Response:
{ "_index" : "book_store", "_type" : "_doc", "_id" : "E2lww30BAtxnt_qoQMJz", "_version" : 1, "result" : "created", "_shards" : { "total" : 2, "successful" : 2, "failed" : 0 }, "_seq_no" : 15, "_primary_term" : 2}
ES的Response也是JSON构造,从其result字段能够得悉咱们曾经胜利在ES中保留了一本书的信息。此外还有三个须要关注的字段:_index、_type和_id,它们别离示意索引(Index)、类型(Type)、文档ID(Document ID)。
- 文档(Document):数据读写的最根本单元,在本例中,一本书就对应一个文档。又比方在电商零碎中,一件商品就对应一个文档。在人事零碎中,一名员工也对应一个文档。每个文档都蕴含一个_id字段,作为文档的标识,它的值在同类型的文档中是惟一的。
- 索引(Index):索引是文档的容器,是一类类似文档的汇合,是文档存储的逻辑单元。
- 类型(Type):在ES的晚期版本,一个索引能够蕴含多个类型,一个类型下蕴含多个文档。但到了7.0版本后,一个索引只能有一个类型,且类型的名字必须是_doc。所以目前类型(Type)曾经没有什么本质的意义。
咱们将ElasticSearch与关系型数据库中的各个概念做一个粗略类比,以便帮忙大家了解:
ElasticSearch | 关系型数据库 |
---|---|
索引(Index)+类型(Type) | 表(Table) |
文档(Document) | 行(Row) |
文档字段(Document Field) | 列(Column) |
文档ID(Document ID) | 主键(Primary Key) |
咱们应用索引book_store存储所有图书的信息,上面的Request示意在索引book_store的_doc类型下保留一本书的信息(类型也只能是_doc):
POST /book_store/_doc{ "ISBN": "9787187651807", "title": "零根底学Java", "description": "零根底自学JAVA编程的入门图书", "price": 66.88, "author": "Poype", "publisher": "极客军营", "stock": 55}
相比于数据库在执行insert操作前须要提前创立好对应的表,应用ES无需在写入文档前创立好对应的索引。如果写入文档时发现对应的索引不存在,ES会主动帮咱们创立好那个索引。
因为在保存文档的时候没有提供惟一ID,ES会为该文档主动生成一个惟一ID作为_id字段的值。
获取文档数据
能够根据上述的文档ID获取一个文档的信息,应用HTTP GET办法向ES服务器发送查问Request,在Request中明确指定索引和文档ID。留神这里的文档ID是由ES随机生成的,所以每次的ID都不一样。
GET /book_store/_doc/FWmJw30BAtxnt_qoj8IE
ES收到该申请后会返回如下Response:
{ "_index" : "book_store", "_type" : "_doc", "_id" : "FWmJw30BAtxnt_qoj8IE", "_version" : 1, "_seq_no" : 16, "_primary_term" : 2, "found" : true, "_source" : { "ISBN" : "9787187651807", "title" : "零根底学Java", "description" : "零根底自学JAVA编程的入门图书", "price" : 66.88, "author" : "Poype", "publisher" : "极客军营", "stock" : 55 }}
Response中蕴含了对该文档阐明的元数据,如咱们曾经介绍过的_index、_type和_id三个字段。此外,found字段为true示意胜利找到了对应的文档。_source字段上面是真正的文档数据。
如果用一个不存在的文档ID发动查问会收到上面的Response,其中found字段为false示意不存在指定ID的文档。
{ "_index" : "book_store", "_type" : "_doc", "_id" : "FWmJw30BAtxnt_qoj81E", "found" : false}
批改文档数据
能够依据文档ID批改已存在的文档。应用HTTP PUT办法发送批改文档的Request:
PUT /book_store/_doc/FWmJw30BAtxnt_qoj8IE{ "ISBN": "9787187651807", "title": "零根底学Java", "description": "零根底自学JAVA编程的入门图书", "price": 55.66, "author": "Poype", "publisher": "极客军营", "stock": 55}
咱们将书的价格从原来的66.88批改为55.66,其它信息放弃不变。ES收到该申请后返回如下后果:
{ "_index" : "book_store", "_type" : "_doc", "_id" : "FWmJw30BAtxnt_qoj8IE", "_version" : 2, "result" : "updated", "_shards" : { ... }, "_seq_no" : 17, "_primary_term" : 2}
result字段为updated示意文档曾经更新胜利。另外须要留神的是_version和_seq_no两个字段,它们的值都有所增加。这两个字段是用来做并发管制的,具体含意在后续章节会有具体介绍。
删除文档
应用HTTP DELETE办法能够删除一个文档,例如删除之前的文档;
DELETE /book_store/_doc/FWmJw30BAtxnt_qoj8IE
ES收到该申请后返回如下Response:
{ "_index" : "book_store", "_type" : "_doc", "_id" : "FWmJw30BAtxnt_qoj8IE", "_version" : 8, "result" : "deleted", "_shards" : { ... }, "_seq_no" : 23, "_primary_term" : 2}
result字段为deleted示意该文档曾经被胜利删除。
全文搜寻
看到这里你兴许会比拟悲观,咱们目前介绍的这些CRUD操作任何数据库也都能反对的很好,那么ES的劣势是什么呢?别急,上面咱们就来看下,相比于传统数据库,ElasticSeach所善于的畛域——全文搜寻(Full Text Search)。
为了更好的对其进行阐明,咱们再向ES多减少几本书的信息:
POST /book_store/_doc/{ "ISBN": "9787111213826", "title": "JAVA编程思维", "description": "JAVA学习经典,殿堂级著述", "price": 89.88, "author": "Bruce Eckel", "publisher": "机械工业出版社", "stock": 231}POST /book_store/_doc/{ "ISBN": "9085115891807", "title": "Python编程,从入门到实际", "description": "零根底学Python编程教程书籍", "price": 82.30, "author": "Eric Matthes", "publisher": "人民邮电出版社", "stock": 121}POST /book_store/_doc/{ "ISBN": "9787115449153", "title": "Elasticsearch实战", "description": "Elasticsearch入门教程书籍", "price": 79, "author": "Radu Gheorghe", "publisher": "人民邮电出版社", "stock": 87}POST /book_store/_doc/{ "ISBN": "9787115472588", "title": "鸟哥的Linux私房菜", "description": "实用Linux零碎利用、开发及运维人员", "price": 98.80, "author": "鸟哥", "publisher": "人民邮电出版社", "stock": 77}
例如一位顾客想搜寻一本对于Java的书。如果是应用关系型数据库,你可能会执行相似上面的SQL帮忙顾客找到想要的书;
select * from book_store where title like %Java%;
这条SQL的性能很差,须要扫描整个表。而且兼容性也不好,例如书名中蕴含java和JAVA的都无奈被检索到。
换作ElasticSearch,能够应用如下的查问命令搜寻Java相干的书籍:
GET /book_store/_doc/_search{ "query": { "match": { "title": "java" } }}
ElasticSearch收到该申请后返回如下后果:
{ "took" : 619, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 2, "relation" : "eq" }, "max_score" : 0.9278223, "hits" : [ { "_index" : "book_store", "_type" : "_doc", "_id" : "GGmpw30BAtxnt_qoXMJq", "_score" : 0.9278223, "_source" : { "ISBN" : "9787111213826", "title" : "JAVA编程思维", "description" : "JAVA学习经典,殿堂级著述", "price" : 89.88, "author" : "Bruce Eckel", "publisher" : "机械工业出版社", "stock" : 231 } }, { "_index" : "book_store", "_type" : "_doc", "_id" : "FWmJw30BAtxnt_qoj8IE", "_score" : 0.9278223, "_source" : { "ISBN" : "9787187651807", "title" : "零根底学Java", "description" : "零根底自学JAVA编程的入门图书", "price" : 55.66, "author" : "Poype", "publisher" : "极客军营", "stock" : 55 } } ] }}
能够看到Response中曾经蕴含了咱们想要的后果。它的兼容性很好,在书名中蕴含Java或JAVA的文档都能被胜利搜寻到。它的性能也很高,即便是很大量的数据,ElasticSearch也能够很快为用户搜寻到想要的数据。
更简单的搜寻
如果有一位顾客,他想买一本学习Java的书,然而他的估算无限,最多只能付70元。所以他想检索Java相干的书籍,且书的售价必须小于70元。相似的搜寻场景在咱们日常生活中很常见,能够通过如下命令实现这个搜寻需要,其中的”lt“示意小于(less than):
GET /book_store/_doc/_search{ "query": { "bool": { "filter": { "range": { "price": { "lt": 70 } } }, "must": { "match": { "title": "java" } } } }}
ES收到该申请后返回如下后果:
{ "took" : 320, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 1, "relation" : "eq" }, "max_score" : 0.9278223, "hits" : [ { "_index" : "book_store", "_type" : "_doc", "_id" : "FWmJw30BAtxnt_qoj8IE", "_score" : 0.9278223, "_source" : { "ISBN" : "9787187651807", "title" : "零根底学Java", "description" : "零根底自学JAVA编程的入门图书", "price" : 55.66, "author" : "Poype", "publisher" : "极客军营", "stock" : 55 } } ] }}
高亮匹配片段
如果又有一位顾客,他心愿找一本经典著作。咱们能够通过搜寻书的形容(description)中含有“经典”二字的文档实现这个需要。
但该顾客不仅心愿能获取到搜寻后果,还心愿可能一眼看出为什么返回给他后果合乎他的要求。个别能够通过在搜寻后果中把关键字加高亮以便让用户一眼就能辨认到。
GET /book_store/_doc/_search{ "query": { "match": { "description": "经典" } }, "highlight": { "fields": { "description": {} } }}
咱们在搜寻命令中用highlight指定了高亮字段的名称,ElasticSearch收到该申请后返回如下后果:
{ ... "hits" : { "total" : { "value" : 1, "relation" : "eq" }, "max_score" : 2.8796844, "hits" : [ { "_index" : "book_store", "_type" : "_doc", "_id" : "GGmpw30BAtxnt_qoXMJq", "_score" : 2.8796844, "_source" : { "ISBN" : "9787111213826", "title" : "JAVA编程思维", "description" : "JAVA学习经典,殿堂级著述", "price" : 89.88, "author" : "Bruce Eckel", "publisher" : "机械工业出版社", "stock" : 231 }, "highlight" : { "description" : [ "JAVA学习<em>经</em><em>典</em>,殿堂级著述" ] } } ] }}
相比于之前的搜寻后果,这次在Response中还蕴含highlight字段。其中应用html标签给匹配的关键字加高亮。但这个高亮加的不是很失当,相比于“经典”,“经典”这种高亮形式才更加正当。大家这里先有个印象,等前面咱们学了分词器,大家就晓得该如何优化这个问题了。
小结
本章通过一个小示例,带大家疾速浏览了ElasticSearch中的一些基本概念。咱们理解了如何与ElasticSearch服务器交互、如何通过Kibana更不便的操作ElasticSearch、如何执行根本的CRUD操作、以及如何实现简略的搜寻需要。上面的章节将正式为大家具体介绍ElasticSearch的各项技术细节。
喜爱本文的敌人,欢送关注公众号极客军营,收看更多精彩内容