text 被用来索引长文本,建立索引钱会将这些文本进行分词
keyword 不需要分词,可以被用来检索过滤、排序、聚合
数学类型:long integer short byte doucle float
日期类型: date
布尔类型:boolean
二进制:binary
数组类型
对象类型 object
等等基本数据类型,还有许多特定类型如地理位置、Ipv4等等 不过多介绍
ElasticSearch使用一种称为倒排索引的结构,它适用于快速的全文检索。一个倒排索引由文档中所有不重复词的列表构成,对于其中每一个词,都有一个包含它的文档列表
示例:
id | 内容 |
---|---|
1 | 小明 |
2 | 小丽 |
3 | 小黑 |
用分词器将内容自动切分成单词序列,每个文档就转换为由单词序列构成的数据流,需要对每个不通给的单词赋予唯一的单词编号,同事记录下哪些文档包含这个单词,由此我们可以得到每个单词的倒排列表,如下
id | 单词 | 倒排列表 |
---|---|---|
1 | 小 | 1,2,3 |
2 | 明 | 1 |
3 | 丽 | 2 |
4 | 黑 | 3 |
倒排列表中可以记录单词出现的频率,即该单词在某个文档中出现次数,如下表格
id | 单词 | 倒排列表 |
---|---|---|
1 | 小 | (1;1),(2;1),(3;1) |
2 | 明 | (1;1) |
3 | 丽 | (2;1) |
4 | 黑 | (3;1) |
倒排列表中还可以记录单词在某个文档中出现的文职信息,如
(1,<1>,1) 表示单词在id为1的文档中出现过一次,位置为1
Hello 和hello,用户会认为他们是相同的词
dog和dogs 他们有相同的词根
jumped和leap 没有相同的词根,但是他们的意思相近,是同义词
以上情况,应该都能被同一种搜索条件搜索到
所以,在建立倒排所以的时候,es会使用标准化规则,以确保上面的例子都能被搜索到。
从一串文本中且分出一个一个的词条,并对没个词条进行标准化。包括三部分:
1.charactre fiter,分词之前的预处理,过滤掉HTML标签,特殊符号转换等
2.tokenizer,分词
3.token filter,标准化(单复数、大小写、同义词等)
1.standard分词器(默认分词器),他会将词汇转换成小写形式,并去除停用词和标点符号,支持中文,采用的方法为单字切分
2.simpl分词器,首先会通过非字母字符来分割文本信息,将词汇单元统一为小写形式,该分词器会去掉数学类型的字符
3.whitespace分词器,仅去掉空格,对字符没有lowcase化,不支持中文,不对生成的词汇单元进行其他标准化处理
4.language分词器,特定语言分词器,不支持中文
PUT /lib/
{
"settings":{
"index":{
"number_of_shards": 3,
"number_of_replicas": 0
}
}
}
/lib/ --索引的名称 ,number_of_shards – 分片的数量,number_of_replicas – 备份的数量
//如果不设置settings 则使用默认配置 number_of_shards为5 ,number_of_replicas为1
PUT /lib/user/1
{
“first_name”:“xiaowang”,
“last_name”:“laowang”,
“age”:55,
“about”:“I like to collect rockalbums”,
“interrests”:[“music”]
}
//在索引lib下添加类型为user,id为1的一条数据
如果不指定id,则使用POST,id由es服务器自动生成
查看索引配置
GET /lib/_settgins
查看所有索引的配置
GET /_all/_settgins
查看指定id的数据
GET /lib/user/1
//指定显示结果集字段
GET /lib/user/1?_source=age,about
多次put会覆盖掉前一次
如果要更新指定字段,则需要post
POST /lib/user/1/_update
{
“doc”:{
“age”:56
}
}
DELETE /lib/user/1 --删除指定数据
DELETE /lib2/ --删除索引
GET /_mget
{
“docs”:[
{
“_index”:“lib”,
“_type”:“user”,
“_id”:1
},
{
“_index”:“lib”,
“_type”:“user”,
“_id”:2
}
]
}
//分别指定不同的字段
GET /_mget
{
“docs”:[
{
“_index”:“lib”,
“_type”:“user”,
“_id”:1,
“_source”:[“age”,“intersts”]
},
{
“_index”:“lib”,
“_type”:“user”,
“_id”:2,
“_source”:“intersts”
}
]
}
//简化写法,也可以单独指定
GET /lib/user/_mget
{
“docs”:[
{
“_id”:1
},
{
“type”:“user2”,
“_id”:2
}
]
}
//如果是同类型的批量获取 还可以再次简化
GET /lib/user/_mget
{
“ids”:[“1”,“2”]
}
//搜索 排序
GET /lib/user/_search?q=last_name:laoli&sort=age:desc
//复杂 条件查询
GET /lib/user/_search
{
“query”:{
“terms”:{
“interests”:[“music”]
}
}
}
//分页
GET /lib/user/_search
{
“from”:0,
“size”:2,
“query”:{
“terms”:{
“interests”:[“music”]
}
}
}
//如果需要显示版本号在上边的json中加入"version":true
GET /lib/user/_search
{
"query":{
"match":{
"name":"zhaoliu tianqi"
}
}
}
会查询出包含zhaoliu、tianqi的所有数据。term和match的主要区别在于,term不使用分词器,对值进行完全匹配,match会对查找条件进行分词,匹配倒排索引。
精确查找使用使用term,匹配查找使用match
//查询全部
GET /lib/user/_search
{
“query”:{
“match_all”: {}
}
}
//多filed查询
GET /lib/user/_search
{
“query”:{
“multi_match”:{
“query”:“laowang,xiaoli”,
“fields”:["last_name,“first_name”]
}
}
}
//短语匹配,匹配指定字段 相当于模糊查询
GET /lib/user/_search
{
"query":{
"match_phrase":{
"last_name":"laowang shi shei"
}
}
}
//指定结果集
GET /lib/user/_search
{
"query":{
"match_all":{}
},
"_source":["last_name","age"]
}
或者
GET /lib/user/_search
{
"query":{
"match_all":{}
},
"_source":{
"includes":"*name",
"excludes": ["age"]
}
}
//排序
GET /lib/user/_search
{
“query”:{
“match_all”:{}
},
“sort”:{
“age”:{
“order”:“asc”
}
}
}
//查询指定日期
GET /lib/user/_search
{
“query”:{
“range”:{
“birthday”:{
“from”:“1991-12-120”,
“to”:“2020-02-20”,
“include_lower”:true,
“include_upper”:false
}
}
}
}
//可以使用通配符*和?
GET /lib/user/_search
{
“query”:{
“wildcard”:{“last_name”:“lao*”}
}
}
GET /lib/user/_search
{
“query”:{
“fuzzy”:{
“last_name”:“liaolii”
}
}
}
同样可以查询出last_name 值为laoli的数据
属性介绍:
must 必须满足
should 满足其中一个即可
must_not 不必满足
只查询满足的条件
GET /lib5/user/_search
{
"query": {
"bool": {
"filter": {
{
"terms":{
"name":"laowang"
}
}
}
}
}
}
满足年龄是25或者生日是2020-02-20,不必满足年龄是30
GET /lib5/user/_search
{
"query": {
"bool": {
"should": [
{"term":{"age":25}},
{"term":{"birthdate":"2020-02-20"}}
],
"must_not": {
"term":{"age":30}
}
}
}
}
GET /lib/user/_search
{
“query”:{
“match”:{
“last_name”:“laoli”
}
},
“highlight”:{
“fields”:{
“last_name”:{}
}
}
}
//会将要高亮显示的字段值用标签包裹
POST /lib2/emp/_bulk
{“index”:{"_id":1}}
{“name”:“xiaowang”,“age”:1}
{“index”:{"_id":2}}
{“name”:“xiaoli”,“age”:2}
//所有操作一起执行
POST /lib2/emp/_bulk
{“delete”:{"_index":“lib2”,"_type":“emp”,"_id":“2”}} --删除
{“create”:{"_index":“lib3”,"_type":“emp”,"_id":“100”}} --创建新的索引和类型并添加
{“name”:“wangwu”}
{“index”:{"_index":“lib3”,"_type":“emp”}} --添加,id由es服务器生成
{“name”:“zhaoliu”}
{“update”:{"_index":“lib2”,"_type":“emp”,"_id":“1”}} – 更新
{“doc”:{“age”:“50”}}
bulk会把要处理的数据载入到内存中,所以数量是有限制的,最佳的数量取决于硬件、文档的大小和复杂性,一般建议1000-5000个文档,大小建议5-15MB,默认不超过100M,可以再es的配置文件中进行配置
es采用了乐观锁来保证数据的一致性,当用户对document进行操作时,需要制定操作的版本,版本号存在冲突时,es会提示冲突并跑异常(VersionConflictEngineException异常)。
内部版本控制使用的是 _version,取值范围 1 -2的63次方-1
外部版本控制:version和version_type=external 配合使用切versioin需要大于es中的version的值
PUT /lib/user/2/?version=4&version_type=external
{
“first_name”:“xiaoli”,
“last_name”:“laoli”,
“age”:55,
“about”:“I like to collect rockalbums”,
“interrests”:[“music”]
}
GET /lib/usr/_mapping 查看指定类型的mapping映射,默认由es服务器生成,es服务器会根据数据自动判断类型,简称动态映射。
GET /lib/user/_search?q=last_name:laoli
默认情况下,数值、日期不进行分词,只有text类型可以分词。
mapping的属性介绍:
index 是否分词
analyzer 指定分词器,默认standard analyzer
search_analyzer 指定搜索时的分词器,同analyzer 相同
ignore_above 文本超过指定值,将会忽略
//自定义mappingd
es默认会为每一个字段都建立倒排索引,如果不需要需要再mappings中添加index=false,这样该字段不会建立倒排索引,也不会被检索。
PUT /lib4
{
“settings”:{
“index”:{
“number_of_shards”: 3,
“number_of_replicas”: 0
}
},
“mappings”:{
“users”:{
“properties”:{
“name”:{“type”:“text”},
“username”:{“type”:“text”,“analyzer”:“standard”},
“carate_time”:{“type”:“date”,“index”:false},
“age”:{“type”:“integer”}
}
}
}
}
//如果多个text类型的field都需要被索引,则在创建mapping的时候,可以将多个field拷贝到一个field,在索引的时候检索这一个字段就可以了,能够显著提升检索性能。
PUT /lib6/user
{
"properties":{
"name":{
"type":"text",
"copy_to":"fullcontents"
},
"address":{
"type":"text",
"copy_to":"fullcontents"
}
}
}
ik带有两个分词器:ik_max_word,会将文本做最细粒度的拆分,尽可能的拆分出词语。ik_smart,会做最粗粒度的拆分,已被拆分的词语不会再次被其他词语占有
PUT /lib5
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 0
},
"mappings": {
"user":{
"properties": {
"name":{"type": "text","analyzer": "ik_max_word"},
"address":{"type": "text","analyzer": "ik_max_word"},
"age":{"type": "integer"},
"interests":{"type": "text","analyzer": "ik_max_word"},
"birthdat":{"type": "date"}
}
}
}
}
如果查询数据量较大,可以使用scroll查询,分批返回数据,达到滚动加载数据的效果,但是他和分页并不是同一个性质,这里要做好区分。
GET /lib7/user/_search?scroll=1m --指定每批查询时间最大为1分钟
{
"query": {
"match_all": {}
},
"sort": ["_doc"], -- 不按默认的相关度排序,提高性能
"size":3 -- 每批次查询3条
}
//每次下旬结果会返回scroll_id,下次查询直接传递该值
GET /_search/scroll
{
"scroll":"1m",
"scroll_id":"DnF1ZXJ5VGhlbkZldGNoAwAAAAAAAAABFmFwWWdERWwxUXJPWEN0SzIzS2duNkEAAAAAAAAAAhZhcFlnREVsMVFyT1hDdEsyM0tnbjZBAAAAAAAAAAMWYXBZZ0RFbDFRck9YQ3RLMjNLZ242QQ=="
}