02、ElasticStack系列,第二章:增删改查与分词

ElasticStack系列,第二章:增删改查与分词

一、ElasticSearch核心内容详解

1、文档

{
    _index: "haoke"
    _type: "user"
    _id: "FD_2gm4BoifuYiH46rUl"
    _version: 1
    found: true
    _source: {
        id: 1002
        name: "李四"
        age: 21
        sex: "男"
    }-
}

元数据:

1、_index	文档存储的地方:
类似于关系型数据库里的“数据库”,它是我们存储和索引关联数据的地方。


2、_type	文档代表的对象的类
在关系型数据库中,我们经常将相同类的对象存储在一个表里,因为它们有着相同的结构。
同理,在Elasticsearch中,我们使用相同类型(type)的文档表示相同的“事物”,
因为他们的数据结构也是相同的。


3、_id		文档的唯一标识
id仅仅是一个字符串,它与 _index 和 _type 组合时,就可以在Elasticsearch中
唯一标识一个文档。当创建一个文档,你可以自定义 _id ,也可以让Elasticsearch
帮你自动生成(32位长度)。

2、查询响应

①、平常查询的时候,相应没有格式化,是这样的:

GET  http://IP:9200/haoke/user/FT_Hh24BoifuYiH4yLVZ 
{"_index":"haoke","_type":"user","_id":"FT_Hh24BoifuYiH4yLVZ","_version":1,"found":true,"_source":{ "id":1002,"name":"李四","age":21, "sex":"女"}}

想要结果格式化在之后加一个?pretty即可:

GET http://IP:9200/haoke/user/FT_Hh24BoifuYiH4yLVZ?pretty 
{
  "_index" : "haoke",
  "_type" : "user",
  "_id" : "FT_Hh24BoifuYiH4yLVZ",
  "_version" : 1,
  "found" : true,
  "_source" : {
    "id" : 1002,
    "name" : "李四",
    "age" : 21,
    "sex" : "女"
  }
}

②、查询只返回数据,不要元数据

请求:

GET http://IP:9200/haoke/user/FT_Hh24BoifuYiH4yLVZ/_source	##斜线

结果:

{ 
    "id":1002, 
    "name":"李四", 
    "age":21, 
    "sex":"女"
}

③、查询只返回指定的字段

请求:

GET http://IP:9200/haoke/user/FT_Hh24BoifuYiH4yLVZ?_source=id,name ##问号

结果:

{
    "_index":"haoke",
    "_type":"user",
    "_id":"FT_Hh24BoifuYiH4yLVZ",
    "_version":1,
    "found":true,
    "_source":{
        "name":"李四",
        "id":1002
    }
}

④、既不返回元数据,也只返回指定字段

请求:

GET http://IP:9200/haoke/user/FT_Hh24BoifuYiH4yLVZ/_source?_source=id,name ##斜线+问号

结果:

{
    "name":"李四",
    "id":1002
}

⑤、判断文档是否存在

请求:

HEAD http://IP:9200/haoke/user/FT_Hh24BoifuYiH4yLVZ

结果:

存在:
	Status: 200 OK    Time: 53ms
不存在:
	Status: 404 NOT Found    Time: 210ms

3、批量操作

①、_mget 查询

A、同一个_index 同一个 _type下

请求:

POST  http://IP:9200/haoke/user/_mget

请求body:
{ 
	"ids" : [ "FT_Hh24BoifuYiH4yLVZ", "Fj_Ih24BoifuYiH4mrUZ" ]
}

结果:

{
    "docs": [
        {
            "_index": "haoke",
            "_type": "user",
            "_id": "FT_Hh24BoifuYiH4yLVZ",
            "_version": 1,
            "found": true,
            "_source": {
                "id": 1002,
                "name": "李四",
                "age": 21,
                "sex": "女"
            }
        },
        {
            "_index": "haoke",
            "_type": "user",
            "_id": "Fj_Ih24BoifuYiH4mrUZ",
            "_version": 1,
            "found": true,
            "_source": {
                "id": 1001,
                "name": "张三",
                "age": 20,
                "sex": "男"
            }
        }
    ]
}

B、同一个_index 不同 _type下

请求:

POST http://IP:9200/haoke/_mget

请求body:
{
	"docs":[
		{
			"_type":"user",##类型1
			"_id":"FT_Hh24BoifuYiH4yLVZ"
		},
		{
			"_type":"user",##类型2
			"_id":"Fj_Ih24BoifuYiH4mrUZ"
		},
	]
}

结果:

{
    "docs": [
        {
            "_index": "haoke",
            "_type": "user",
            "_id": "FT_Hh24BoifuYiH4yLVZ",
            "_version": 1,
            "found": true,
            "_source": {
                "id": 1002,
                "name": "李四",
                "age": 21,
                "sex": "女"
            }
        },
        {
            "_index": "haoke",
            "_type": "user",
            "_id": "Fj_Ih24BoifuYiH4mrUZ",
            "_version": 1,
            "found": true,
            "_source": {
                "id": 1001,
                "name": "张三",
                "age": 20,
                "sex": "男"
            }
        }
    ]
}

C、不同_index 和 不同 _type下

请求:

POST http://IP:9200/_mget

请求body:
{
	"docs":[
		{
			"_index":"haoke",##索引1
			"_type":"user",##类型1
			"_id":"FT_Hh24BoifuYiH4yLVZ"
		},
		{
			"_index":"haoke",##索引2
			"_type":"user",##类型2
			"_id":"Fj_Ih24BoifuYiH4mrUZ"
		}
	]
}

结果:

{
    "docs": [
        {
            "_index": "haoke",
            "_type": "user",
            "_id": "FT_Hh24BoifuYiH4yLVZ",
            "_version": 1,
            "found": true,
            "_source": {
                "id": 1002,
                "name": "李四",
                "age": 21,
                "sex": "女"
            }
        },
        {
            "_index": "haoke",
            "_type": "user",
            "_id": "Fj_Ih24BoifuYiH4mrUZ",
            "_version": 1,
            "found": true,
            "_source": {
                "id": 1001,
                "name": "张三",
                "age": 20,
                "sex": "男"
            }
        }
    ]
}

D、可以具体的字段

请求:

POST http://IP:9200/_mget

请求body:
{
	"docs":[
		{
			"_index":"haoke",
			"_type":"user",
			"_id":"FT_Hh24BoifuYiH4yLVZ",
			"_source":"name"
		},
		{
			"_index":"haoke",
			"_type":"user",
			"_id":"Fj_Ih24BoifuYiH4mrUZ",
			"_source":["name","age"]
		}
	]
}

结果:

{
    "docs": [
        {
            "_index": "haoke",
            "_type": "user",
            "_id": "FT_Hh24BoifuYiH4yLVZ",
            "_version": 1,
            "found": true,
            "_source": {
                "name": "李四"
            }
        },
        {
            "_index": "haoke",
            "_type": "user",
            "_id": "Fj_Ih24BoifuYiH4mrUZ",
            "_version": 1,
            "found": true,
            "_source": {
                "name": "张三",
                "age": 20
            }
        }
    ]
}
②、_bulk 增删改

格式:

{ action: { metadata }}
{ request body		  }

{ action: { metadata }}
{ request body        }

A、批量添加

请求:

http://IP:9200/_bulk

请求body:
{"create":{"_index":"haoke","_type":"user","_id":"aaa"}}
{"id":1001,"name":"name1","age":20,"sex":"男"}
{"create":{"_index":"haoke","_type":"user","_id":"bbb"}}
{"id":1002,"name":"name2","age":21,"sex":"女"}
{"create":{"_index":"haoke","_type":"user","_id":"ccc"}}
{"id":1003,"name":"name3","age":22,"sex":"女"}

或者:

{"index":{"_index":"haoke","_type":"user","_id":"aaa"}}
{"id":1001,"name":"name1","age":20,"sex":"男"}
{"index":{"_index":"haoke","_type":"user","_id":"bbb"}}
{"id":1002,"name":"name2","age":21,"sex":"女"}
{"index":{"_index":"haoke","_type":"user","_id":"ccc"}}
{"id":1003,"name":"name3","age":22,"sex":"女"}

结果:

在这里插入图片描述

B、批量删除

请求:

POST http://IP:9200/_bulk

请求body:
{"delete":{"_index":"haoke","_type":"user","_id":"aaa"}}
{"delete":{"_index":"haoke","_type":"user","_id":"bbb"}}
{"delete":{"_index":"haoke","_type":"user","_id":"ccc"}}

结果:
在这里插入图片描述

C、批量修改–全量覆盖修改

请求:

http://IP:9200/_bulk

请求body:

{"index":{"_index":"haoke","_type":"user","_id":"aaa"}}
{"id":1001,"name":"name111","age":20,"sex":"男"}
{"index":{"_index":"haoke","_type":"user","_id":"bbb"}}
{"id":1002,"name":"name222","age":21,"sex":"女"}
{"index":{"_index":"haoke","_type":"user","_id":"ccc"}}
{"id":1003,"name":"name333","age":22,"sex":"女"}

结果:

在这里插入图片描述

D、批量修改-局部修改

请求:

http://IP:9200/_bulk

请求body:
{"update":{"_index":"haoke","_type":"user","_id":"aaa"}}
{"doc":{"name":"name111a"}}
{"update":{"_index":"haoke","_type":"user","_id":"bbb"}}
{"doc":{"name":"name222b"}}
{"update":{"_index":"haoke","_type":"user","_id":"ccc"}}
{"doc":{"name":"name333c"}}

结果:

在这里插入图片描述

总结:

一次请求多少性能最高?

整个批量请求需要被加载到接受我们请求节点的内存里,所以请求越大,给其它请求可用的内存就越小。
有一个最佳的bulk请求大小。超过这个大小,性能不再提升而且可能降低。


最佳大小,当然并不是一个固定的数字。它完全取决于你的硬件、你文档的大小和复杂度以及索引和搜索的负载。


幸运的是,这个最佳点(sweetspot)还是容易找到的:试着批量索引标准的文档,随着大小的增长,当性能开始降低,
说明你每个批次的大小太大了。开始的数量可以在1000~5000个文档之间,如果你的文档非常大,可以使用较小的批次。


通常着眼于你请求批次的物理大小是非常有用的。一千个1kB的文档和一千个1MB的文档大不相同。
一个好的批次最好保持在5-15MB大小间。

4、分页

和SQL使用 LIMIT 关键字返回只有一页的结果一样,Elasticsearch接受 from 和 size 参数:

size: 结果数,默认10
from: 跳过开始的结果数,默认0

如果你想每页显示5个结果,页码从1到3,那请求如下:

GET /_search?size=5
GET /_search?size=5&from=5
GET /_search?size=5&from=10

注意:

应该当心分页太深或者一次请求太多的结果。结果在返回前会被排序。但是记住一个搜索请求常常涉及多个分片。
每个分片生成自己排好序的结果,它们接着需要集中起来排序以确保整体排序正确。

为了理解为什么深度分页是有问题的,让我们假设在一个有5个主分片的索引中搜索。当我们请求结果的第一页
(结果1到10)时,每个分片产生自己最顶端10个结果然后返回它们给请求节点(requesting node),
它再排序这所有的50个结果以选出顶端的10个结果。现在假设我们请求第1000页——结果10001到10010。
工作方式都相同,不同的是每个分片都必须产生顶端的10010个结果。然后请求节点排序这50050个结果并丢
弃50040个!你可以看到在分布式系统中,排序结果的花费随着分页的深入而成倍增长。这也是为什么网络搜
索引擎中任何语句不能返回多于1000个结果的原因。

5、映射

前面我们创建的索引以及插入数据,都是由Elasticsearch进行自动判断类型,有些时候我们是需要进行明确字段类型的,否则,自动判断的类型和实际需求是不相符的。自动判断的规则如下:

JSON typeField type
Boolean: true or false“boolean”
Whole number: 123“long”
Floating point: 123.45“double”
String, valid date: “2014-09-15”“date”
String: “foo bar”“string”

Elasticsearch中支持的类型如下:

类型表示的数据类型
Stringstring , text , keyword
Whole numberbyte , short , integer , long
Floating pointfloat , double
Booleanboolean
Datedate
  • string类型在ElasticSearch 旧版本中使用较多,从ElasticSearch 5.x开始不再支持string,由text和keyword类型替代。
  • text 类型,当一个字段是要被全文搜索的,比如Email内容、产品描述,应该使用text类型。设置text类型以后,字段内容会被分析,在生成倒排索引以前,字符串会被分析器分成一个一个词项。text类型的字段不用于排序,很少用于聚合。【要被分词】
  • keyword类型适用于索引结构化的字段,比如email地址、主机名、状态码和标签。如果字段需要进行过滤(比如查找已发布博客中status属性为published的文章)、排序、聚合。keyword类型的字段只能通过精确值搜索到。【不参与分词】

使用:

##插入索引,并创建映射
PUT /lee
{
    "settings":{
        "index":{
            "number_of_shards":"2",
            "number_of_replicas":"0"
        }
    },
    "mappings":{
        "person":{
            "properties":{
                "name":{
                    "type":"text"
                },
                "age":{
                    "type":"integer"
                },
                "mail":{
                    "type":"keyword"
                },
                "hobby":{
                    "type":"text"
                }
            }
        }
    }
}

##查看映射
GET /lee/_mapping

插入一些数据,后面要用到:

GET /lee/_mapping

{"index":{"_index":"itcast","_type":"person"}}
{"name":"张三","age": 20,"mail": "111@qq.com","hobby":"羽毛球、乒乓球、足球"}
{"index":{"_index":"itcast","_type":"person"}}
{"name":"李四","age": 21,"mail": "222@qq.com","hobby":"羽毛球、乒乓球、足球、篮球"}
{"index":{"_index":"itcast","_type":"person"}}
{"name":"王五","age": 22,"mail": "333@qq.com","hobby":"羽毛球、篮球、游泳、听音乐"}
{"index":{"_index":"itcast","_type":"person"}}
{"name":"赵六","age": 23,"mail": "444@qq.com","hobby":"跑步、游泳"}
{"index":{"_index":"itcast","_type":"person"}}
{"name":"孙七","age": 24,"mail": "555@qq.com","hobby":"听音乐、看电影"}

在这里插入图片描述

6、结构化查询

①、term

term 主要用于精确匹配哪些值,比如**“数字”,“日期",“布尔值” 或 “不能分词的字符串”**(未经分析的文本数据类型):

{ "term": { "age": 26} } 
{ "term": { "date":"2014-09-01"} } 
{ "term": { "public": true} } 
{ "term": { "tag": "full_text"} }

示例:(查询年龄为20的person)

POST /lee/person/_search

{
    "query":{
        "term":{
            "age":20
        }
    }
}

注意:

不能匹配text
②、terms

terms 跟 term 有点类似,但 terms 允许指定多个匹配条件。 如果某个字段指定了多个值,那么文档需要一起去做匹配:( 类似SQL中的 in )

示例:(查询年龄为20,21,22的person)

POST /lee/person/_search

{
    "query":{
        "terms":{
            "age":[ 20,21,22]
        }
    }
}
③、range

range 过滤允许我们按照指定范围查找一批数据:

符号意义
gt大于
gte大于等于
lt小于
lte小于等于

示例:(查询年龄大于等于20小于等于22的人)

POST /lee/person/_search

{
    "query":{
        "range":{
            "age":{
                "gte":20,
                "lte":22
            }
        }
    }
}
④、exists

exists 查询可以用于查找文档中是否包含指定字段或没有某个字段,类似于SQL语句中的 IS_NULL 条件**(字段是否存在)**

语法:

{
	"query":{
		"exists":{
			"field":"字段"
		}
	}
}

示例:

POST http://IP:9200/lee/person/_search

{
	"query":{
		"exists":{
			"field":"gender"
		}
	}
}
⑤、match

match 查询是一个标准查询,不管你需要全文本查询还是精确查询基本上都要用到它。

A、如果你使用 match 查询一个**“全文本字段”,它会在真正查询之前用“分词器”**先分析 match 一下查询字符:

B、如果用 match 下指定了一个确切值,在遇到数字,日期,布尔值或者 不分词的字符串时,它将为你搜索你给定的值:

{ "match": { "age": 26 }}
{ "match": { "date":"2014-09-01" }}
{ "match": { "public": true }}
{ "match": { "tag": "full_text"  }}
⑥、bool

bool 查询可以用来合并多个条件查询结果的布尔逻辑

包含以下几个操作符

操作符意义
must多个查询条件的完全匹配,相当于 and
must_not多个查询条件的相反匹配,相当于 not
should至少有一个查询条件匹配, 相当于 or

示例:

{
	"query":{
		"bool":{
			"must":{
				"range":{
					"age":{
						"gt":20,
						"lte":22
					}
				}
			},
			"must_not":{
				"term":{  ##注意不能匹配name,因为name是text,可分词的
					"age":21
				}
			}
		}
	}
}
⑦、filter

前面讲过结构化查询,Elasticsearch也支持过滤查询,如term、range、match等。

示例:(查询年龄为20岁的用户)

{
	"query":{
		"bool":{
			"filter":{
				"term":{
					"age":20
				}
			}
		}
	}
}

查询和过滤的对比:

  • 一条过滤语句会询问每个文档的字段值是否包含着特定值。
  • 查询语句会询问每个文档的字段值与特定值的匹配程度如何。
    • 一条查询语句会计算每个文档与查询语句的相关性,会给出一个相关性评分 _score,并且 按照相关性对匹配到的文档进行排序。 这种评分方式非常适用于一个没有完全配置结果的全文本搜索。
  • 一个简单的文档列表,快速匹配运算并存入内存是十分方便的, 每个文档仅需要1个字节。这些缓存的过滤结果集与后续请求的结合使用是非常高效的。
  • 查询语句不仅要查找相匹配的文档,还需要计算每个文档的相关性,所以一般来说查询语句要比 过滤语句更耗时,并且查询结果也不可缓存。

建议:

做精确匹配搜索时,最好用过滤语句,因为过滤语句可以缓存数据。

二、中文分词

分词就是指将一个文本转化成一系列单词的过程,也叫文本分析,在Elasticsearch中称之为Analysis。

指定分词器进行分词:

POST /_analyze
请求body:
{
    "analyzer":"standard",##标准分词器
    "text":"hello world"##待分词的内容
}

结果:
{
    "tokens": [
        {
            "token": "hello",
            "start_offset": 0,
            "end_offset": 5,
            "type": "<ALPHANUM>",
            "position": 0
        },
        {
            "token": "world",
            "start_offset": 6,
            "end_offset": 11,
            "type": "<ALPHANUM>",
            "position": 1
        }
    ]
}

指定索引分词

POST /lee/_analyze

请求body:
{
    "analyzer":"standard",
    "filed":"hobby",
    "text":"听音乐"
}

结果:
{
    "tokens": [
        {
            "token": "听",
            "start_offset": 0,
            "end_offset": 1,
            "type": "<IDEOGRAPHIC>",
            "position": 0
        },
        {
            "token": "音",
            "start_offset": 1,
            "end_offset": 2,
            "type": "<IDEOGRAPHIC>",
            "position": 1
        },
        {
            "token": "乐",
            "start_offset": 2,
            "end_offset": 3,
            "type": "<IDEOGRAPHIC>",
            "position": 2
        }
    ]
}

中文分词的难点在于,在汉语中没有明显的词汇分界点,如在英语中,空格可以作为分隔符,如果分隔不正确就会造成歧义。

常用中文分词器,IK、jieba、THULAC等,推荐使用IK分词器。

IK分词器 Elasticsearch插件地址:https://github.com/medcl/elasticsearch-analysis-ik

IK分词器安装:

将elasticsearch-analysis-ik-6.5.4.zip 安装到 es的plugin目录的ik目录下
1、创建ik目录
cd /es/plugin
mkdir ik

2、解压
unzip elasticsearch-analysis-ik-6.5.4.zip
(unzip命令不可用的,安装yum install -y unzip zip)

3、启动
su elsearch  ##切换elsearch用户
cd es/bin
./elasticsearch -d

测试中文分词:

POST /_analyze

#请求body
{
    "analyzer":"ik_max_word",
    "text":"我是中国人"
}

##结果:
{
    "tokens": [
        {
            "token": "我",
            "start_offset": 0,
            "end_offset": 1,
            "type": "CN_CHAR",
            "position": 0
        },
        {
            "token": "是",
            "start_offset": 1,
            "end_offset": 2,
            "type": "CN_CHAR",
            "position": 1
        },
        {
            "token": "中国人",
            "start_offset": 2,
            "end_offset": 5,
            "type": "CN_WORD",
            "position": 2
        },
        {
            "token": "中国",
            "start_offset": 2,
            "end_offset": 4,
            "type": "CN_WORD",
            "position": 3
        },
        {
            "token": "国人",
            "start_offset": 3,
            "end_offset": 5,
            "type": "CN_WORD",
            "position": 4
        }
    ]
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值