ElasticSearch是一个基于Lucene的搜索服务器,它提供了一个分布式多用户能力的全文搜索引擎,它是基于RESTful web接口的,采用java开发,并作为Apache许可条款下的开源发布,是当前流行的企业级搜索引擎。
Elasticsearch是面向文档(document oriented)的,这意味着它可以存储整个对象或文档(document)。然而它不仅仅是存储,还会索引(index)每个文档的内容使之可以被搜索。在Elasticsearch中,你可以对文档(而非成行成列的数据)进行索引、搜索、排序、过滤。Elasticsearch比传统关系型数据库如下:
Relational DB ‐> Databases ‐> Tables ‐> Rows ‐> Columns
Elasticsearch ‐> Indices‐> Types‐> Documents ‐> Fields
在ElasticSearch中,提供了功能丰富的restful api操作,包括CURD操作和创建索引,删除索引等。
首先需要打开ElasticSearch服务,访问127.0.0.1:9200
出现下面界面表示打开成功:
然后安装elasticsearch-head
插件,安装成功后如下:
最后安装postman
应用或者安装Advanced REST Client
谷歌浏览器插件,都是用来发送http请求的。linux安装postmanl链接
创建一个简单的空索引,索引的名字为blog
,如下:
采用put
的方式,url为服务地址加上索引的名称,请求参数如下:
{
"settings":{
"index":{
"number_of_shards":"2",
"number_of_replicas":"0"
}
}
}
number_of_shards
为片数,number_of_replicas
为副本数。点击发送之后,状态码为200表示创建成功,刷新可以看到多了一个blog索引:
向索引blog1中插入一条user类型的数据时,_id设置为1001,请求地址为http://127.0.0.1:9200/blog1/user/1001
,采用post方式。也可以不设置_id,就会使用自动生成的_id,这是一条数据的唯一标识符。
{
"id":1001,
"name":"张三",
"age":20,
"sex":"男"
}
会出现错误如下,说名这个索引是只读状态。
{
"error": {
"root_cause": [
{
"type": "cluster_block_exception",
"reason": "index [blog1] blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];"
}
],
"type": "cluster_block_exception",
"reason": "index [blog1] blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];"
},
"status": 403
}
解决方法,终端运行下面命令:
curl -XPUT -H "Content-Type: application/json" http://127.0.0.1:9200/blog1/_settings -d '{"index.blocks.read_only_allow_delete": null}'
或者在postman中执行PUT http://127.0.0.1:9200/blog1/_settings
{
"index.blocks.read_only_allow_delete": null
}
其中,blog1换成你的索引名称,也可以换成_all
表示所有索引。
再次发送请求,响应结果如下,表示插入数据成功:
{
"_index": "blog1",
"_type": "user",
"_id": "1001",
"_version": 3,
"result": "updated",
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"_seq_no": 2,
"_primary_term": 2
}
注:这是非结构化的索引,不需要事先创建,直接插入数据默认创建索引。
在elasticsearch中,文档数据是不可以修改的,但是可以通过覆盖的方式进行更新。
PUT http://127.0.0.1:9200/blog1/user/1001
{
"id":1001,
"name":"张三",
"age":23,
"sex":"女"
}
查看数据,如图以及修改了:
数据虽然被更新了,但是确实全部数据的覆盖,那么能不能局部更新呢,其实是可以的,在内部,依然会查询到这个文档数据,然后进行覆盖,步骤如下:
1.从旧文档中检索json
2.进行修改
3.删除旧文档
4.索引新文档
如下,把年龄更改为26,请求地址为http://127.0.0.1:9200/blog1/user/1001/_update
POST http://127.0.0.1:9200/blog1/user/1001/_update
{
"doc":{
"age":26
}
}
删除数据只需要在postman中执行DELETE http://127.0.0.1:9200/blog1/user/1001
即可,相应的数据如下,表示删除成功。
{
"_index": "blog1",
"_type": "user",
"_id": "1001",
"_version": 7,
"result": "deleted",
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"_seq_no": 6,
"_primary_term": 2
}
注:删除一个文档不会立即从磁盘上移除,只是被标记为已删除状态,Elasticsearch会在你之后添加更多索引的时候在后台进行删除内容的清理。
1.搜索一条数据:只需要执行GET http://127.0.0.1:9200/blog1/user/1001
即可,其中1001是_id
返回结果如下:
{
"_index": "blog1",
"_type": "user",
"_id": "1001",
"_version": 1,
"_seq_no": 7,
"_primary_term": 2,
"found": true,
"_source": {
"id": 1001,
"name": "张三",
"age": 23,
"sex": "女"
}
}
2.搜索全部数据:GET http://127.0.0.1:9200/blog1/user/_search
,默认返回10条数据。
3.关键字搜索:例如根据年龄搜索,GET http://127.0.0.1:9200/blog1/user/_search?q=age:23
返回的数据:
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 2,
"successful": 2,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "blog1",
"_type": "user",
"_id": "1001",
"_score": 1.0,
"_source": {
"id": 1001,
"name": "张三",
"age": 23,
"sex": "女"
}
}
]
}
}
Elasticsearch提供了丰富且灵活的查询语叫做DSL查询,它允许构建更加复杂,强大的查询。post http://127.0.0.1:9200/blog1/user/_search
{
"query":{
"match":{
"age":23
}
}
}
响应数据:
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 2,
"successful": 2,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "blog1",
"_type": "user",
"_id": "1001",
"_score": 1.0,
"_source": {
"id": 1001,
"name": "张三",
"age": 23,
"sex": "女"
}
}
]
}
}
查询年龄大于20岁,姓名为男的数据,请求体如下:
{
"query":{
"bool":{
"filter":{
"range":{
"age":{
"gt":20
}
}
},
"must":{
"match":{
"sex":"男"
}
}
}
}
}
返回结果:
{
"took": 24,
"timed_out": false,
"_shards": {
"total": 2,
"successful": 2,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 0.2876821,
"hits": [
{
"_index": "blog1",
"_type": "user",
"_id": "1001",
"_score": 0.2876821,
"_source": {
"id": 1002,
"name": "李四",
"age": 25,
"sex": "男"
}
},
{
"_index": "blog1",
"_type": "user",
"_id": "jmsZD20Bk9NfkJ2KxpRa",
"_score": 0.18232156,
"_source": {
"id": 1004,
"name": "张三",
"age": 21,
"sex": "男"
}
}
]
}
}
全文搜索,请求体如下:
{
"query":{
"match":{
"name":"张三 李四"
}
}
}
搜索结果为:
{
"took": 13,
"timed_out": false,
"_shards": {
"total": 2,
"successful": 2,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1.3862944,
"hits": [
{
"_index": "blog1",
"_type": "user",
"_id": "jmsZD20Bk9NfkJ2KxpRa",
"_score": 1.3862944,
"_source": {
"id": 1004,
"name": "张三",
"age": 21,
"sex": "男"
}
},
{
"_index": "blog1",
"_type": "user",
"_id": "1001",
"_score": 0.5753642,
"_source": {
"id": 1002,
"name": "李四",
"age": 25,
"sex": "男"
}
}
]
}
}
请求体
{
"query":{
"match":{
"name":"张三 李四"
}
},
"highlight":{
"fields":{
"name":{}
}
}
}
返回结果:
{
"took": 72,
"timed_out": false,
"_shards": {
"total": 2,
"successful": 2,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1.3862944,
"hits": [
{
"_index": "blog1",
"_type": "user",
"_id": "jmsZD20Bk9NfkJ2KxpRa",
"_score": 1.3862944,
"_source": {
"id": 1004,
"name": "张三",
"age": 21,
"sex": "男"
},
"highlight": {
"name": [
"张三"
]
}
},
{
"_index": "blog1",
"_type": "user",
"_id": "1001",
"_score": 0.5753642,
"_source": {
"id": 1002,
"name": "李四",
"age": 25,
"sex": "男"
},
"highlight": {
"name": [
"李四"
]
}
}
]
}
}
这里涉及到中文分词的问题,将在以后谈到
请求体:
{
"aggs":{
"all_interests":{
"terms":{
"field":"age"
}
}
}
}
响应结果:
{
"took": 50,
"timed_out": false,
"_shards": {
"total": 2,
"successful": 2,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "blog1",
"_type": "user",
"_id": "jGsYD20Bk9NfkJ2K1JRX",
"_score": 1.0,
"_source": {
"id": 1003,
"name": "王五",
"age": 18,
"sex": "男"
}
},
{
"_index": "blog1",
"_type": "user",
"_id": "jmsZD20Bk9NfkJ2KxpRa",
"_score": 1.0,
"_source": {
"id": 1004,
"name": "张三",
"age": 21,
"sex": "男"
}
},
{
"_index": "blog1",
"_type": "user",
"_id": "kGsnD20Bk9NfkJ2KRZTb",
"_score": 1.0,
"_source": {
"id": 1005,
"name": "赵六",
"age": 21,
"sex": "男"
}
},
{
"_index": "blog1",
"_type": "user",
"_id": "1001",
"_score": 1.0,
"_source": {
"id": 1002,
"name": "李四",
"age": 25,
"sex": "男"
}
}
]
},
"aggregations": {
"all_interests": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 21,
"doc_count": 2
},
{
"key": 18,
"doc_count": 1
},
{
"key": 25,
"doc_count": 1
}
]
}
}
}
上半部分是查询的数据,下半部分是根据年龄进行的聚合统计。