ElasticSearch 初学

ES环境搭建视频

什么是全文索引

  • 扫码文本全部词句,建立对应的索引,并记录词句的位置与次数.
  • 用户查询词句,通过建立的索引进行筛选,返回给用户展示

什么是倒排索引

  • 正排索引是根据数据id 找到内容
  • 倒排索引则是根据内容找数据id

什么是分词

  • 将文本拆分成单个字或词语
    在这里插入图片描述

分词器有哪些(自带的)

  • Standard Analyzer

    • 默认分词器
    • 按词切分,支持多语言
    • 小写处理
    • 支持中文采用的方法为单字切分
  • Simple Analyzer

    • 按照非字母切分
    • 小写处理
  • Whitespace Analyzer

    • 空白字符作为分隔符
  • Stop Analyzer

    • 相比Simple Analyzer多了去除请用词处理
  • 停用词指语气助词等修饰性词语,如the, an, 的, 这等

    • Keyword Analyzer
    • 不分词,直接将输入作为一个单词输出
  • Pattern Analyzer

    • 通过正则表达式自定义分隔符
    • 默认是\W+,即非字词的符号作为分隔符

中文分词器

  • 难点
    • 中文分词指的是将一个汉字序列切分为一个一个的单独的词。在英文中,单词之间以空格作为自然分界词,汉语中词没有一个形式上的分界符
    • 上下文不同,分词结果迥异,比如交叉歧义问题
  • 常见分词系统
    • IK:实现中英文单词的切分,可自定义词库,支持热更新分词词典
    • jieba:支持分词和词性标注,支持繁体分词,自定义词典,并行分词等
    • Hanlp:由一系列模型与算法组成的Java工具包,目标是普及自然语言处理在生产环境中的应用
    • THUAC:中文分词和词性标注

ElasticSearch基本概念

关系型数据库 VS ElasticSearch

  • 在7.0之前,一个 Index可以设置多个Types
  • 目前Type已经被Deprecated,7.0开始,一个索引只能创建一个Type - “_doc”
  • 传统关系型数据库和Elasticsearch的区别:
    • Elasticsearch- Schemaless /相关性/高性能全文检索
    • RDMS —事务性/ Join

索引(Index)

  • 一个索引就是一个拥有几分相似特征的文档的集合。比如说,可以有一个客户数据的索引, 另一个产品目录的索引,还有一个订单数据的索引。
  • 一个索引由一个名字来标识(必须全部是小写字母的),并且当我们要对对应于这个索引中 的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。

文档(Document)

  • Elasticsearch是面向文档的,文档是所有可搜索数据的最小单位。
    • 日志文件中的日志项
    • 一本电影的具体信息/一张唱片的详细信息
    • MP3播放器里的一首歌/一篇PDF文档中的具体内容
  • 文档会被序列化成JSON格式,保存在Elasticsearch中
    • JSON对象由字段组成
    • 每个字段都有对应的字段类型(字符串/数值/布尔/日期/二进 制/范围类型)
  • 每个文档都有一个Unique ID
    • 可以自己指定ID或者通过Elasticsearch自动生成(建议ES生成)
  • 一篇文档包含了一系列字段,类似数据库表中的一条记录
  • JSON文档,格式灵活,不需要预先定义格式
    • 字段的类型可以指定或者通过Elasticsearch自动推算
    • 支持数组/支持嵌套
  • 文档元数据
    • _index:文档所属的索引名
    • _type:文档所属的类型名
    • _id:文档唯—ld
    • _source: 文档的原始Json数据
    • _version: 文档的版本号,修改删除操作_version都会自增1
    • _seq_no: 和_version一样,一旦数据发生更改,数据也一直是累计的。 Shard级别严格递增,保证后写入的Doc的_seq_no大于先写入的Doc的_seq_no。
    • _primary_term: _primary_term主要是用来恢复数据时处理当多个文档的 _seq_no一样时的冲突,避免Primary Shard上的写入被覆盖。每当Primary Shard 发生重新分配时,比如重启,Primary选举等,_primary_term会递增1。

ElasticSearch索引操作

创建索引

索引命名必须小写,不能以下划线开头
格式: PUT /索引名称

  #创建索引 
  PUT /es_db 

  #创建索引时可以设置分片数和副本数 
  PUT /es_db 
  { 
    "settings" : {
      "number_of_shards" : 3, 
      "number_of_replicas" : 2 
    } 
  }
  
  #修改索引配置 
  PUT /es_db/_settings 
  { 
    "index" : { 
      "number_of_replicas" : 1 
    } 
  }

查询索引

格式: GET /索引名称

  #查询索引 
  GET /es_db 

  #es_db是否存在 
  HEAD /es_db

删除索引

格式: DELETE /索引名称

  #DELETE /es_db

ElasticSearch文档操作

示例数据

  PUT /es_db
  {
      "settings" : {
          "index" : {
              "analysis.analyzer.default.type": "ik_max_word"
          }
      }
  }
  
  PUT /es_db/_doc/1
  {
  "name": "张三",
  "sex": 1,
  "age": 25,
  "address": "广州天河公园",
  "remark": "java developer"
  }
  PUT /es_db/_doc/2
  {
  "name": "李四",
  "sex": 1,
  "age": 28,
  "address": "广州荔湾大厦",
  "remark": "java assistant"
  }
  
  PUT /es_db/_doc/3
  {
  "name": "王五",
  "sex": 0,
  "age": 26,
  "address": "广州白云山公园",
  "remark": "php developer"
  }
  
  PUT /es_db/_doc/4
  {
  "name": "赵六",
  "sex": 0,
  "age": 22,
  "address": "长沙橘子洲",
  "remark": "python assistant"
  }
  
  PUT /es_db/_doc/5
  {
  "name": "张龙",
  "sex": 0,
  "age": 19,
  "address": "长沙麓谷企业广场",
  "remark": "java architect assistant"
  }	
      
  PUT /es_db/_doc/6
  {
  "name": "赵虎",
  "sex": 1,
  "age": 32,
  "address": "长沙麓谷兴工国际产业园",
  "remark": "java architect"
  }	

添加(索引)文档

格式: [PUT | POST] /索引名称/[_doc | _create ]/id

# 创建文档,指定id
# 如果id不存在,创建新的文档,否则先删除现有文档,再创建新的文档,版本会增加
  PUT /es_db/_doc/1
  {
  "name": "张三",
  "sex": 1,
  "age": 25,
  "address": "广州天河公园",
  "remark": "java developer"
  }	
  
  #创建文档,ES生成id
  POST /es_db/_doc
  {
  "name": "张三",
  "sex": 1,
  "age": 25,
  "address": "广州天河公园",
  "remark": "java developer"
  }

注意:POST和PUT都能起到创建/更新的作用,PUT需要对一个具体的资源进行操作也就是要确定id才能进行更新/创建,而POST是可以针对整个资源集合进行操作的,如果不写id就由ES生成一个唯一id进行创建新文档,如果填了id那就针对这个id的文档进行创建/更新
注意:Create -如果ID已经存在,会失败

修改文档

# 全量更新,替换整个json
  PUT /es_db/_doc/1/
  {
  "name": "张三",
  "sex": 1,
  "age": 25
  }

全量更新,整个json都会替换,格式: [PUT | POST] /索引名称/_doc/id
注意:如果文档存在,现有文档会被删除,新的文档会被索引

  • 使用_update部分更新,格式: POST /索引名称/_update/id
    • update不会删除原来的文档,而是实现真正的数据更新
# 部分更新:在原有文档上更新
# update -文档必须已经存在,更新只会对相应字段做增量修改
  POST /es_db/_update/1
  {
    "doc": {
      "age": 28
    }
  }
  • 使用 _update_by_query 更新文档
  POST /es_db/_update_by_query
  {
    "query": { 
      "match": {
        "_id": 1
      }
    },
    "script": {
      "source": "ctx._source.age = 30"
    }
  }

并发场景下修改文档

_seq_no和_primary_term是对_version的优化,7.X版本的ES默认使用这种方式控制版本,所以当在高并发环境下使用乐观锁机制修改文档时,要带上当前文档的_seq_no和_primary_term进行更新:

  POST /es_db/_doc/2?if_seq_no=21&if_primary_term=6
  {
    "name": "李四xxx"
  }

注意:如果版本号不对,会抛出版本冲突异常

查询文档

  • 根据id查询文档,格式: GET /索引名称/_doc/id
  GET /es_db/_doc/1
  • 搜索文档, 格式: GET /索引名称/_doc/_search
  GET /es_db/_doc/_search
  • ES Search API提供了两种条件查询搜索方式
    • REST风格的请求URI,直接将参数带过去
  #通过URI搜索,使用“q”指定查询字符串,“query string syntax” KV键值对
  
  #条件查询, 如要查询age等于28岁的 _search?q=*:***
  GET /es_db/_doc/_search?q=age:28
  
  #范围查询, 如要查询age在25至26岁之间的 _search?q=***[** TO **] 注意: TO 必须为大写
  GET /es_db/_doc/_search?q=age[25 TO 26]
  
  #查询年龄小于等于28岁的 :<=
  GET /es_db/_doc/_search?q=age:<=28
  #查询年龄大于28前的 :>
  GET /es_db/_doc/_search?q=age:>28
  
  #分页查询 from=*&size=*
  GET /es_db/_doc/_search?q=age[25 TO 26]&from=0&size=1
  
  #对查询结果只输出某些字段 _source=字段,字段
  GET /es_db/_doc/_search?_source=name,age
  
  #对查询结果排序 sort=字段:desc/asc
  GET /es_db/_doc/_search?sort=age:desc
  • 封装到request body中,这种方式可以定义更加易读的JSON格式
  GET /es_db/_search
  {
    "query": {
      "match": {
        "address": "广州白云"
      }
    }
  }

删除文档

  • 根据id删除文档 格式:DELETE /索引名称/_doc/id
  DELETE /es_db/_doc/1

ElasticSearch文档批量操作

批量操作可以减少网络连接所产生的开销,提升性能

注意: 这种批量处理操作没有事务

  • 支持在一次API调用中,对不同的索引进行操作
  • 可以在URI中指定Index,也可以在请求的Payload中进行
  • 操作中单条操作失败,并不会影响其他操作
  • 返回结果包括了每一条操作执行的结果

批量写入

批量对文档进行写操作是通过_bulk的API来实现的

  • 请求方式:POST
  • 请求地址:_bulk
  • 请求参数:通过_bulk操作文档,一般至少有两行参数(或偶数行参数)
    • 第一行参数为指定操作的类型及操作的对象(index,type和id)
    • 第二行参数才是操作的数据
actionName:表示操作类型,主要有 create, index, delete 和 update
  POST _bulk
  { "index" : { "_index" : "test", "_id" : "1" } }
  { "field1" : "value1" }
  
  { "delete" : { "_index" : "test", "_id" : "2" } }
  { "create" : { "_index" : "test2", "_id" : "3" } }
  { "field1" : "value3" }
  
  { "update" : {"_id" : "1", "_index" : "test"} }
  { "doc" : {"field2" : "value2"} }
  注意 Bulk 请求体的数据量不宜过大,建议在 5~15M

批量读取

es的批量查询可以使用 _mget 和 _msearch 两种。其中 _mget 是需要我们知道它的id,可以指定不同的index,也可以指定返回值source。_msearch可以通过字段查询来进行一个批量的查找

  • _mget
  #可以通过ID批量获取不同index和type的数据
  GET _mget
  {
  "docs": [
  {
  "_index": "es_db",
  "_id": 1
  },
  {
  "_index": "article",
  "_id": 4
  }
  ]
  }
  
  #可以通过ID批量获取es_db的数据
  GET /es_db/_mget
  {
  "docs": [
  {
  "_id": 1
  },
  {
  "_id": 4
  }
  ]
  }
  #简化后
  GET /es_db/_mget 
  {
   "ids":["1","2"]  
  }
  • _msearch
  GET /es_db/_msearch
  {} # 索引名称,不写的话就是 URI 中的索引
  {"query" : {"match_all" : {}}, "from" : 0, "size" : 2}
  {"index" : "article"}
  {"query" : {"match_all" : {}}}

文档映射Mapping

Mapping类似数据库中的schema的定义,作用如下:

  • 定义索引中的字段的名称
  • 定义字段的数据类型,例如字符串,数字,布尔等
  • 字段,倒排索引的相关配置(Analyzer)
    ES中Mapping映射可以分为动态映射和静态映射。

动态映射

在关系数据库中,需要事先创建数据库,然后在该数据库下创建数据表,并创建表字段、类型、长度、主键等,最后才能基于表插入数据。
而Elasticsearch中不需要定义Mapping映射(即关系型数据库的表、字段等),在文档写入Elasticsearch时,会根据文档字段自动识别类型,这种机制称之为动态映射。

静态映射

静态映射是在Elasticsearch中也可以事先定义好映射,包含文档的各字段类型、分词器等,这种方式称之为静态映射。

Dynamic Mapping类型自动识别

#创建文档(ES根据数据类型, 会自动创建映射)
PUT /user/_doc/1
{
  "name":"fox",
  "age":32,
  "address":"长沙麓谷"
}

#获取文档映射
GET /user/_mapping

修改文档字段类型限制

  • 新增加字段
    • dynamic 设为 true 时,一旦有新增字段的文档写入,Mapping 也同时被更新
    • dynamic 设为 false,Mapping 不会被更新,新增字段的数据无法被索引,但是信息会出现在 _source 中
    • dynamic 设置成strict(严格控制策略),文档写入失败,抛出异常
  • 对已有字段,一旦已经有数据写入,就不再支持修改字段定义
    • Lucene 实现的倒排索引,一旦生成后,就不允许修改
    • 如果希望改变字段类型,可以利用 reindex API,重建索引
      原因:
      如果修改了字段的数据类型,会导致已被索引的数据无法被搜索
      但是如果是增加新的字段,就不会有这样的影响

对已有字段的mapping修改

  • 具体方法:
    • 如果要推倒现有的映射, 你得重新建立一个静态索引
    • 然后把之前索引里的数据导入到新的索引里
    • 删除原创建的索引
    • 为新索引起个别名, 为原索引名
PUT /user2
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "address": {
        "type": "text",
        "analyzer": "ik_max_word"
      }
    }
  }
}
# 导到新索引里
POST _reindex
{
"source": {
"index": "user"
},
"dest": {
"index": "user2"
}
}
# 删除原索引
DELETE /user
# 新索引 别名 原索引
PUT /user2/_alias/user

GET /user
注意: 通过这几个步骤就实现了索引的平滑过渡,并且是零停机

常用Mapping参数配置

  • index: 控制当前字段是否被索引,默认为true。如果设置为false,该字段不可被搜索

  • 有四种不同基本的index options配置,控制倒排索引记录的内容:

    • docs : 记录doc id
    • freqs:记录doc id 和term frequencies(词频)
    • positions: 记录doc id / term frequencies / term position
    • offsets: doc id / term frequencies / term posistion / character offsets
      text类型默认记录postions,其他默认为 docs。记录内容越多,占用存储空间越大
  • null_value: 需要对Null值进行搜索,只有keyword类型支持设计Null_Value

  • copy_to:将字段的数值拷贝到目标字段,满足一些特定的搜索需求。copy_to的目标字段不出现在_source中。

# 设置copy_to
DELETE /address
PUT /address
{
  "mappings" : {
      "properties" : {
        "province" : {
          "type" : "keyword",
          "copy_to": "full_address"
        },
        "city" : {
          "type" : "text",
          "copy_to": "full_address"
        }
      }
    },
    "settings" : {
        "index" : {
            "analysis.analyzer.default.type": "ik_max_word"
        }
    }
}

PUT /address/_bulk
{ "index": { "_id": "1"} }
{"province": "湖南","city": "长沙"}
{ "index": { "_id": "2"} }
{"province": "湖南","city": "常德"}
{ "index": { "_id": "3"} }
{"province": "广东","city": "广州"}
{ "index": { "_id": "4"} }
{"province": "湖南","city": "邵阳"}

GET /address/_search
{
  "query": {
    "match": {
      "full_address": {
        "query": "湖南常德",
        "operator": "and"
      }
    }
  }
}

Index Template 索引模板

Index Templates可以帮助你设定Mappings和Settings,并按照一定的规则,自动匹配到新创建的索引之上

  • 模版仅在一个索引被新创建时,才会产生作用。修改模版不会影响已创建的索引
  • 你可以设定多个索引模版,这些设置会被“merge”在一起
  • 你可以指定“order”的数值,控制“merging”的过程

Index Template 的工作方式

当一个索引被新创建时:

  • 应用Elasticsearch 默认的settings 和mappings
  • 应用order数值低的lndex Template 中的设定
  • 应用order高的 Index Template 中的设定,之前的设定会被覆盖
  • 应用创建索引时,用户所指定的Settings和 Mappings,并覆盖之前模版中的设定

Dynamic Template

根据es识别的数据类型,结合字段名称,来动态设定字段类型。

  • 我们可以利用Dynamic Template做出
    • 所有字符创类型都设定成Keyword类型,或者关闭Keyword
    • is开头的地段都设置成boolean
    • long_开头的都设置成long类型
PUT my_index
{
  "mappings": {
    "dynamic_templates": [
            {
        "strings_as_boolean": {
          "match_mapping_type":"string",
          "match":"is*",
          "mapping": {
            "type": "boolean"
          }
        }
      },
      {
        "strings_as_keywords": {
          "match_mapping_type":   "string",
          "mapping": {
            "type": "keyword"
          }
        }
      }
    ]
  }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值