Elasticsearch自学(一)

1. Elasticsearch相关概念

官方文档
Elasticsearch 是一个建立在全文搜索引擎 Apache Lucene™ 基础上的搜索引擎,可以说 Lucene 是当今最先进,最高效的全功能开源搜索引擎框架。
Elasticsearch是一个实时分布式开源全文搜索分析引擎
它可以从RESTful Web服务接口访问,并使用模式少JSON(JavaScript对象符号)文档来存储数据。它是基于Java编程语言,这使Elasticsearch能够在不同的平台上运行。使用户能够以非常快的速度来搜索非常大的数据量。

1.1 优势

  • 高效性: 采用倒排索引的方式,从而进行高效的搜索
  • 横向扩展性: 只需要增加服务器,添加配置并入ElasticSearch集群中
  • 分片机制提供更好的分布性: 同一个索引分成多个分片(sharding),分而治之的方式可以提高效率
  • 高可用: 提供副本(Replica)机制,一个分片可以设置多个复制,使得单个节点挂掉的情况,集群照常允许

1.2 主要概念

  • 节点 - 它指的是Elasticsearch的单个正在运行的实例。单个物理和虚拟服务器容纳多个节点,这取决于其物理资源的能力,如RAM,存储和处理能力。
  • 集群 - 它是一个或多个节点的集合。 集群为整个数据提供跨所有节点的集合索引和搜索功能。
  • 索引 - 它是不同类型的文档和文档属性的集合。索引还使用分片的概念来提高性能。 例如,一组文档包含社交网络应用的数据。
  • 类型/映射 - 它是共享同一索引中存在的一组公共字段的文档的集合。 例如,索引包含社交网络应用的数据,然后它可以存在用于用户简档数据的特定类型,另一类型可用于消息的数据,以及另一类型可用于评论的数据。
  • 文档 - 它是以JSON格式定义的特定方式的字段集合。每个文档都属于一个类型并驻留在索引中。每个文档都与唯一标识符(称为UID)相关联。
  • 碎片 - 索引被水平细分为碎片。这意味着每个碎片包含文档的所有属性,但包含的数量比索引少。水平分隔使碎片成为一个独立的节点,可以存储在任何节点中。主碎片是索引的原始水平部分,然后这些主碎片被复制到副本碎片中。
  • 副本 - Elasticsearch允许用户创建其索引和分片的副本。 复制不仅有助于在故障情况下增加数据的可用性,而且还通过在这些副本中执行并行搜索操作来提高搜索的性能。

1.3 Elasticsearch和RDBMS之间的比较

Elasticsearch关系数据库
索引数据库
碎片碎片
映射(Type)
文档(Documents)
字段字段
JSON对象元组

1.4 docker中安装Elastic Search

Elasticsearch Download
Elasticsearch install on docker

docker pull docker.elastic.co/elasticsearch/elasticsearch:7.9.2
docker run --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:7.9.2
docker start/stop elasticsearch

http://localhost:9200/
在这里插入图片描述

1.5 ElasticSearch的9200和9300端口区别

9200作为Http协议,主要用于外部通讯

比如: http://localhost:9200/study/user/1
在这里插入图片描述

9300作为Tcp协议,ES集群之间进行通讯,jar之间就是通过tcp协议通讯

2. Kibana

2.1 Kibana介绍

Kibana 是为 Elasticsearch设计的开源分析和可视化平台。你可以使用 Kibana 来搜索,查看存储在 Elasticsearch 索引中的数据并与之交互。你可以很容易实现高级的数据分析和可视化,以图表的形式展现出来

2.2 Docker中安装Kibana

Elastic Install kibana on docker

docker pull docker.elastic.co/kibana/kibana:7.9.2

docker run --name kibana --link 63406af0f5b5:elasticsearch -p 5601:5601 docker.elastic.co/kibana/kibana:7.9.2

http://localhost:5601/

3. ES乐观锁控制并发

在Elasticsearch通过“_version ”来记录文档的版本,在文档创建时会有一个初始version,默认为1。在对文档进行修改和删除时,version会递增,也可以由用户指定。只有当版本号大于当前版本时,才会修改删除成功,否则失败。当并发请求时,先修改成功的,version会增加,这个时候其他请求就会犹豫version不匹配从而修改失败。

4. Elasticsearch倒排索引

4.1 正向索引

总而言之是通过key,去找value; 用户在主页上搜索关键词“华为手机”时,假设只存在正向索引(forward index),那么就需要扫描索引库中的所有文档,找出所有包含关键词“华为手机”的文档,再根据打分模型进行打分,排出名次后呈现给用户。
弊端: 因为互联网上收录在搜索引擎中的文档的数目是个天文数字,这样的索引结构根本无法满足实时返回排名结果的要求。

4.2 倒排索引

搜索引擎会将正向索引重新构建为倒排索引,即把文件ID对应到关键词的映射转换为关键词到文件ID的映射,每个关键词都对应着一系列的文件,这些文件中都出现这个关键词。

得到倒排索引的结构如下:
“关键词1”:“文档1”的ID,“文档2”的ID,…………。
“关键词2”:带有此关键词的文档ID列表。

单词—文档矩阵
在这里插入图片描述
从纵向即文档这个维度来看,每列代表文档包含了哪些单词,比如文档1包含了词汇1和词汇4,而不包含其它单词。从横向即单词这个维度来看,每行代表了哪些文档包含了某个单词。比如对于词汇1来说,文档1和文档4中出现过单词1,而其它文档不包含词汇1。矩阵中其它的行列也可作此种解读。

倒排索引简单实例

假设文档集合包含五个文档
在这里插入图片描述
中文和英文等语言不同,单词之间没有明确分隔符号,所以首先要用分词系统将文档自动切分成单词序列。这样每个文档就转换为由单词序列构成的数据流,为了系统后续处理方便,需要对每个不同的单词赋予唯一的单词编号,同时记录下哪些文档包含这个单词,在如此处理结束后,我们可以得到最简单的倒排索引(参考图3-4)。在图4中,“单词ID”一栏记录了每个单词的单词编号,第二栏是对应的单词,第三栏即每个单词对应的倒排列表。比如单词“谷歌”,其单词编号为1,倒排列表为{1,2,3,4,5},说明文档集合中每个文档都包含了这个单词。
在这里插入图片描述
相对复杂的倒排索引
相当于基本索引系统比,在单词对应的倒排列表中不仅记录了文档编号,还记载了单词频率信息(TF),即这个单词在某个文档中的出现次数,之所以要记录这个信息,是因为词频信息在搜索结果排序时,计算查询和文档相似度是很重要的一个计算因子,所以将其记录在倒排列表中,以方便后续排序时进行分值计算。
在这里插入图片描述

5. ElasticSearch DSL 介绍

Elasticsearch提供了基于JSON的完整查询DSL(特定于域的语言)来定义查询。将查询DSL视为查询的AST(抽象语法树),它由两种子句组成:

  • 叶子查询子句
    叶查询子句中寻找一个特定的值在某一特定领域,如 matchtermrange查询。这些查询可以自己使用。
  • 复合查询子句
    复合查询子句包装其他叶查询或复合查询,并用于以逻辑方式组合多个查询(例如 bool或dis_max查询),或更改其行为(例如 constant_score查询)。
    查询子句的行为会有所不同,具体取决于它们是在 查询上下文中还是在过滤器上下文中使用。
    我们在使用ElasticSearch的时候,避免不了使用DSL语句去查询,就像使用关系型数据库的时候要学会SQL语法一样。如果我们学习好了DSL语法的使用,那么在日后使用和使用Java Client调用时候也会变得非常简单。

5.1 REST 增删改查:

methodurl地址描述
PUTlocalhost:9200/索引名称/类型名称/文档id创建文档(指定文档id)
POSTlocalhost:9200/索引名称/类型名称创建文档(随机文档id)
POSTlocalhost:9200/索引名称/类型名称/文档id/_update修改文档
DELETElocalhost:9200/索引名称/类型名称/文档id删除文档
GETlocalhost:9200/索引名称/类型名称/文档id查询文档通过文档id
POSTlocalhost:9200/索引名称/类型名称/_search查询所有数据

5.1 Kibana 增删改查

索引:

## Create Index
PUT study
## Create Index with setting
PUT test1
{
    "settings" : {
        "number_of_shards" : 10,
        "number_of_replicas" : 1,
        "refresh_interval" : "1s"
    },
    "mappings" : {
        "_doc" : {
            "properties" : {
                "age" : { "type" : "long" },
                "sex" : { "type" : "text" },
                "message" : { "type" : "keyword" },
                "sendtime" : {  
                  "type" : "date",
                  "format" : "yyyy-MM-dd HH:mm:ss" 
                 }      
            }
        }
    }
}
## View Index
GET study/
## setting(设置选项)
GET study/_settings
## mapping(数据结构)
GET study/_mapping

注:

  • number_of_shards: 是设置的分片数,设置之后无法更改!
  • refresh_interval: 是设置es缓存的刷新时间,如果写入较为频繁,但是查询对实时性要求不那么高的话,可以设置高一些来提升性能。可以更改
  • number_of_replicas : 是设置该索引库的副本数,建议设置为1以上。

其中这里还有几个重要参数也顺便说一下:

  • store: true/false 表示该字段是否存储,默认存储。
  • doc_values: true/false 表示该字段是否参与聚合和排序。
  • index: true/false 表示该字段是否建立索引,默认建立。

## Post 若URL没有ID可自动生成ID
POST study/user/9
{
  "name":"xiaoming",
  "age":20,
  "sex":"F"
}
## Insert Data POST/PUT
PUT study/user/3
{
  "name":"Payne3",
  "age":10,
  "sex":"M"
}
## 查询所有数据
GET study/user/_search

GET study/user/_search
{
  "query": {
    "match_all": {}
  }
}

## 只查询name&age属性
GET study/user/_search
{
  "query": {
    "match_all": {}
  },
  "_source": ["name","age"]
}
## 根据ID查询数据
GET study/user/_mget
{
  "ids":[1,"2"]
}

##  根据属性查询数据
GET study/user/_search?q=age:30
GET study/user/_search?q=age:[10 TO 30]

## 根据属性查询数据
## 查询年龄等于30
GET study/user/_search?q=age:30
## 查询年龄在10到30之间的数据
GET study/user/_search?q=age:[10 TO 30]
## 排序
GET study/user/_search?q=age:[10 TO 30]&sort=age:desc

GET study/user/_search?q=age:[10 TO 30]
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "age": {
        "order": "asc"
      }
    }
  ]
## 5.6 分页
GET study/user/_search?q=age:[10 TO 30]&from=0&size=2

GET study/user/_search
{
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ],
  "from":0,
  "size":2
}

term:
是代表完全匹配,即不进行分词器分析,文档中必须包含整个搜索的词汇

GET study/user/_search
{
  "query": {
    "term": {
      "name":"payne"
    }
  }
}

Issue: 当查询字段是字符串时,并且传入的子串带有大写字母,这时候使用term精确查询无论字段类型是keyword还是text都是查询不到结果的

elasticsearch在创建倒排索引时,就已经将大写转为小写,而后写入索引;

进一步优化查询,因为是精准查询,不需要查询进行评分计算,只希望对文档进行包括或排除的计算,所以我们会使用 constant_score 查询以非评分模式来执行 term 查询并以一作为统一评分。推荐如下查询

GET study/user/_search
{
  "query": {
    "constant_score" : {  
           "filter" : {  
              "term" : {  
                  "name":"payne"
              }
            }  
        }  
    }
  }
}

match:
根据字段的分词器进行分词查询

GET study/user/_search
{
  "query": {
    "match": {
      "name":"payne"
    }
  }
}

bool查询

GET study/user/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "Payne"
          }
        },
        {
          "match": {
            "age": 30
          }
        }
      ]
    }
  }
}

must: 必须匹配,与and等价。贡献算分
must_not:必须不匹配,与not等价,常过滤子句用,但不贡献算分
should: 选择性匹配,至少满足一条,与 OR 等价。贡献算分
filter: 过滤子句,必须匹配,但不贡献算分

查询分词器的分词结果

GET _analyze
{
  "tokenizer" : "standard",
  "text" : "Payne YU"
}

GET _analyze
{
  "tokenizer" : "standard",
  "filter": [{"type": "length", "min":2, "max":4 }],  
  "text" : "this is a test"
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值