Elasticsearch kibana一些基本概念

Elasticsearch 动态创建mapping

如果在创建index的时候不指定mapping,那么ES会帮我们动态创建mapping,那么String数据类型的数据会被映射成text类型(这种类型默认是分词的,在搜索的时候只需要指定部分内容就可以搜到结果)。如果不动态创建mapping,指定字段类型是keyword,那么在搜索的时候需要精确匹配内容,才可以把结果搜出来(底层依然使用倒排索引,只不过索引的字段是整个内容)

Elasticsearch Object数据类型

我们新建一个index:

PUT article
{
  "mappings": {
    "type": {
      "properties": {
        "title": {
          "type": "keyword"
        },
        "author": {
          "properties": {
            "name": {
              "type": "keyword"
            },
            "age": {
              "type": "long"
            }
          }
        }
      }
    }
  }
}

这里面的author字段属于Object类型,下面有name和age字段。
当我们添加一条数据时:

POST article/type
{
  "title": "hello world",
  "author": {
    "name": "Bill Gates",
    "age": 50
  }
}

Object数据类型的底层存储形式:

{
  "title": ["hello world"],
  "author.name": ["Bill Gates],
  "author.age": [50]
}

当添加的数据是如下形式:

POST article/type
{
  "title": "CS",
  "author": [
    {"name":"Tuling","age":70},
    {"name":"yaoqizhi","age":65}
    ]
}

那么Object的存储形式是:

{
  "title": "CS",
  "author.name": ["Tuling", "yaoqizhi"],
  "author.age": [70, 65]
}

Term/Terms

term/terms查询会去倒排索引中查询确切的关键词,并不知道分词器的存在,这种查询适合keyword、date、numeric类型

Match

match 会对我们这个搜索的字段进行分词,然后在倒排索引中进行查找。同时所查找的字段的数据类型不能是keyword。
例如下面的index:

PUT article2
{
  "mappings": {
    "type": {
      "properties": {
        "title": {
          "type": "text"
        },
        "author": {
          "properties": {
            "name": {
              "type": "keyword"
            },
            "age": {
              "type": "long"
            }
          }
        }
      }
    }
  }
}

添加数据

POST article2/type
{
  "title": "system",
  "author": {
    "name": "Tom",
    "age": 52
  }
}

POST article2/type
{
  "title": "operator",
  "author": {
    "name": "jerry",
    "age": 12
  }
}

使用match搜索:

GET article2/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "title": "system operator"
          }
        }
      ]
    }
  }
}

搜索结果如下:

"hits": {
    "total": 2,
    "max_score": 0.2876821,
    "hits": [
      {
        "_index": "article2",
        "_type": "type",
        "_id": "Dgu-oW0BKTSW7lTxmSgP",
        "_score": 0.2876821,
        "_source": {
          "title": "system",
          "author": {
            "name": "Tom",
            "age": 52
          }
        }
      },
      {
        "_index": "article2",
        "_type": "type",
        "_id": "Dwu-oW0BKTSW7lTxoyhT",
        "_score": 0.2876821,
        "_source": {
          "title": "operator",
          "author": {
            "name": "jerry",
            "age": 12
          }
        }
      }
    ]
  }

此时,当title的类型是text时,使用match才会生效。
如果使用term查询:

GET article2/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "title": {
              "value": "system operator"
            }
          }
        }
      ]
    }
  }
}

这样是查询不到的,因为要精确匹配system operator,而文档中没有这个词。

Multi_match

可以指定多个字段,matc只能指定一个字段

match_phrase

短语匹配,类似于英语中的短语

ik分词器

带有两个分词器:

  • ik_max_word: 会将文本做最细粒度的拆分;尽可能多的拆分出词语
  • ik_smart: 会做最粗粒度的拆分;已经被分出的词语将不会被其他词语占用

Filter

filter不计算相关性的,同时可以缓存,因此速度快与query。
新建index,并插入数据:

PUT order
{
  "mappings": {
    "type": {
      "properties": {
        "customsID": {
          "type": "keyword"
        },
        "price": {
          "type": "keyword"
        },
        "orderID": {
          "type": "keyword"
        }
      }
    }
  }
}

POST order/type/_bulk
{"index":{}}
{"customsID":"001","price":"100", "orderID":"10000"}
{"index":{}}
{"customsID":"002","price":"40", "orderID":"10002"}
{"index":{}}
{"customsID":"002","price":"75", "orderID":"10003"}

查询价格是40的数据:

GET order/_search
{
  "query": {
    "bool": {
      "filter": {
        "term": {
          "price": "40"
        }
      }
    }
  }
}

查询结果如下:

"hits": {
    "total": 1,
    "max_score": 0,
    "hits": [
      {
        "_index": "order",
        "_type": "type",
        "_id": "EgvxoW0BKTSW7lTx3iiD",
        "_score": 0,
        "_source": {
          "customsID": "002",
          "price": "40",
          "orderID": "10002"
        }
      }
    ]
  }

既然可以用term,那么就可以使用terms

constant_score

当我们不关心检索词频率TF(Term Frequency)对搜索结果排序的影响时,可以使用constant_score将查询语句query或者过滤语句filter包装起来。
检索词频率:检索词在该字段出现的频率。出现频率越高,相关性也越高。字段中出现过5次要比只出现过1次的相关性高。
假设存在如下类型的文档:

{ "description": "wifi wifi garden pool" }

查询语句如下:

{
    "query":{
        "bool":{
            "should": [
                { "constant_score": {
                      "query": { "match": { "description": "wifi" }}
                }},
                { "constant_score": {
                      "query": { "match": { "description": "garden" }}
                }},
                { "constant_score": {
                      "query": { "match": { "description": "pool" }}
                }}
              ]
        }
    }
}

因为不考虑检索词频率,所以匹配文档的score等于该文档含有的不同检索词汇的个数。
score受到协调因子boost的影响:

{ "constant_score": {
    "boost":2,
    "query": { "match": { "description": "pool" }}
}}

出现pool的文档score加2。
score还需要考虑反向文档频率IDF的影响,最后得分可以不是整数。
反向文档频率:每个检索词在索引中出现的频率。频率越高,相关性越低。 检索词出现在多数文档中会比出现在少数文档中的权重更低, 即检验一个检索词在文档中的普遍重要性。

Rebalance

当新增一个节点时,ES集群会自动把一些shard分配到这个新的节点

节点对等

每一个节点(包括master节点和data节点)都可以接收请求,如果要查询的数据在当前节点的shard中不存在,那么会将请求路由到其他节点,其他节点查询后将结果返回给原来的节点,最后返回给应用程序。

primary shard和replica shard

每一个document肯定只存在于一个primary shard和对应的replica shard中,不可能存在多个primary shard中。
primary shard在创建index时之后就不可以改变了,而replica shard可以在后续更改

ES容错机制

当es集群中有一个节点宕机,并且这个节点包含primary shard,那么会把其余节点上对应的replica shard提升为primary shard

ES更新

es更新文档时,当出现并发问题时,内部使用乐观锁,也就是说通过版本控制(也就是说version)的方式,解决并发冲突的问题。此外如果使用retry_on_confict=次数时会从新获取最新版本的文档数据,然后再去进行更新,如果失败之后,会再次尝试这一步骤,次数自己指定。

ES数据路由的原理

一个索引由多个primary shard构成。此时如果添加一个document,那么这个document一定会存储在某一个primary shard中的,ES通过数据路由机制确定这个document存储在那个shard中。
路由算法:
shard=hash(routing) % number_of_primary_shards
示例:一个索引,3个primary shard

  1. 当每次增删改查时,有一个routing值,默认是文档doc_id值
  2. 对这个routing值使用hash函数进行计算
  3. 算出的值再和primary_shards个数取余数
    余数肯定在0~(number_of_primary_shards-1)之间,文档就在对应的shard上
    如果手动指定doc_id对负载均衡和提高批量读写的性能都有帮助

ES增删改原理

示例:一个索引,三个分片,一个副本。
如下图:当我们往ES中添加一条数据时,可以任选一个节点进行添加数据操作,假设我们往node1中添加数据,那么此时node1被称为协调节点,因为我们要添加节点时,这个文档不一定是要存在node1中,而是需要根据数据路由算法来决定这个数据应该往哪个分片存。
在这里插入图片描述
协调节点会根据数据路由算法,算出文档应该存在哪个primary shard中。假设经过计算这条数据应该存在P1上。然后协调节点会将数据进行转发,将数据转发到node2中的P1上,到达P1后存储数据,并把数据同步到副本R1上。
一系列操作之后,由协调节点对应用程序进行响应。

写一致性原理和quorum机制

对es进行增删改都数据写操作,当进行写操作时,可以使用参数consistency=
consistency的取值有以下三种:

  • one:(primary shard) 只要有一个primary shard是活跃的就可以执行
  • all:(all shard)所有的primary shard和replica shard都是活跃的才能执行
  • quorum:(default)默认值,大部分shards是活跃的才能执行,(例如共有6个shard,至少有3个shard活跃时才能执行写操作)

quorum机制:int((number_of_primary_shard + number_of_replica)/2) + 1
例如: 3个primary shard,1个replica
int((3+1)/2) + 1=3,因此至少要3个shard活跃时才可以写操作。
案例:当只有一个node,一个primary shard,一个replica时,此时集群状态时yellow,只有一个primary shard活跃,而quorum=(1+1)/2 + 1 = 2,因此此时无法进行增删改操作。
案例:当我们有两个node,一个primary shard,三个replica时,此时集群状态是yellow,而quorum=(1+3)/2 + 1 = 3,因此此时同样能无法进行增删改操作。
当活跃的shard的个数没有达到要求时,es默认会等待一分钟,如果在等待时间内活跃的shard数量没有增加,则显示timeout。

文档查询原理

第一步:查询请求发给任意一个节点,该节点就成了协调节点(coodinating node),然后该节点使用路由算法算出文档所在的primary shard
第二步:协调节点把请求转发给primary shard也可以转发给replica shard(使用轮训算法(Round-Robin-Schedule)把请求平均分配给primary shard和replica shard)
第三步:处理请求的节点把结果返回给协调节点,协调节点再返回给应用程序
特殊情况:请求的文档还在建立的过程中,primary shard上存在,而replica shard上不存在,但是请求被转发到了replica shard中,这时就会提示找不到文档。

返回数据根据设置的timeout来返回

当数据量比较大时,用户可以设置返回多长时间的数据。虽然不能返回所有的数据,但是可以提高响应速度。不至于让用户等待太长时间,而返回所有数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值