Elasticsearch 笔记

集群(cluster)、节点(node)和分片(shard)

Elasticsearch也是使用Java编写并使用Lucene来建立索引并实现搜索功能,但是它的目的是通过简单连贯的RESTful API让全文搜索变得简单并隐藏Lucene的复杂性。

Elasticsearch的优点:
Elasticsearch不仅仅是Lucene和全文搜索引擎,它还提供:
分布式的实时文件存储,每个字段都被索引并可被搜索
实时分析的分布式搜索引擎
可以扩展到上百台服务器,处理PB级结构化或非结构化数据

ELasticsearch提供两种内置客户端用于你的代码:
(1)节点客户端(node client): 
节点客户端以无数据节点(none data node)身份加入集群,换言之,它自己没有数据,但是知道什么数据位于集群的哪个节点上,能够直接转发请求到对应的节点上。

(2)传输客户端(Transport client):
更轻量的传输客户端能够发送请求到远程集群,它自己不加入集群,只是简单转发请求给集群中的节点。

两个Java客户端都通过9300端口与集群交互,使用Elasticsearch传输协议(Elasticsearch Transport Protocol)。集群中的节点也通过9300端口通信。如果此端口未开放,你的节点将不能形成集群。

在Elasticsearch中存储数据的行为叫做索引(indexing)

---------------------------------------------------------
和传统数据库对比:
关系数据库(RelationalDB)->库(Databases)->表(Tables)   ->行(Rows)             ->列(Columns)
                   Elasticsearch-> 索引(Indices)  ->类型(Types)->文档(Documents)->字段(Fields)
---------------------------------------------------------

Elasticsearch集群可以包含多个索引(indices)(数据库),这些库可以包含多个类型(types)(表),这些类型包含多个文档(documents)(行),然后每个文档包含多个字段(Fields)(列)。

索引(名词)
如上文所述,一个索引(index)像是传统关系数据库中的数据库,它是相关文档存储的地方,index的复数是indices或indexes。
索引(动词)
“索引一个文档”表示存储一个文档在索引(名词)里,以便它可以被检索或者查询。这很像SQL中的"INSERT"关键字,差别是,如果文档已经存在,新的文档将覆盖旧的文档。
反向索引
传统数据库为特定列增加一个索引(index),例如多路搜索树(B-Tree)索引来加速检索。Elasticsearch和Lucene使用一种叫做反向索引(inverted index)的结构来实现相同目的。
通常文档中的所有字段会被索引(拥有反向索引),因此他们可以被搜索。如果一个字段没有反向索引不能被搜索。

Elasticsearch查询关键字:

match
{
 "query" : {
      "match":{ "last_name":"Smith" } //查询姓中包含smith的记录
  }
}

姓氏为“Smith”的员工,但是我们只想得到年龄大于30岁的员工:

{
"query"    :    {
   "filtered" : {
    "filter" : {
               "range"    : {
                   "age" : { "gt" : 30 }
           }
        },
    "query" : {
              "match":{ "last_name":"Smith" } //查询姓中包含smith的记录
          }
    }
}
}

查询结果中_score代表相关度,ES查询后会按相关度进行排序
短语(phrases)
我们想要查询    about     包
含完整短语“rock    climbing”的员工。
为了实现以上效果,我们将查询 match 变更为    match_phrase  :

{
 "query" : {
    "match_phrase"    : {
        "about"    : "rock    climbing"
      }

     }
}


高亮(highlight)匹配到的关键字

{
"query"    : {
    "match_phrase"    : {
       "about" : "rock climbing"
     }
},
"highlight":    {
    "fields" : {
       "about" : {}
    }
}
}


结果会得到一个新的叫做    highlight 的部分,这里包括了 about 字段中匹
配的文本片段,并且用<em></em>包围匹配到的单词。

Elasticsearch把这项功能叫做聚合(aggregations),它允许你在数据基础上生成复杂的统计。它很像SQL中的"GROUP BY" 但是功能更强大
例如:按interests分组,然后统计每组下的平均年龄:

{
    "aggs"    : {
        "all_interests"    : {
                    "terms" :    { "field" : "interests"    },
             "aggs" :    {
                     "avg_age" : {
                   "avg" :  { "field" : "age"    }
                     }
                    }
        }
        }
}


es扩展:
横向扩展:购买更多的服务器 它通过增加节点来传播负载和增加可靠性
纵向扩展:购买更好的服务器

一个节点(node)就是一个Elasticsearch实例,而一个集群(cluster)由一个或多个节点组成,它们具有相同的cluster.name,
它们协同工作,分享数据和负载。当有新的节点加入或者删除节点,集群就会感知到并平衡数据。
集群中一个节点会被选举为主节点(master),它用来管理集群中的一些变更,例如新建或删除索引、增加或移除节点等。主节点不需要参与文档级别的更改或搜索,
意味着只有一个主节点不会随着流量的增长而成为集群的瓶颈

status 字段提供一个整体的标识来指示集群的功能是否可用。三种颜色表示:

green     所有主要和复制的分片都可用
yellow     所有主分片可用,但不是所有复制分片都可用
red     不是所有的主分片都可用

索引(index)——一个存储关联数据的地方。实际上,索引只是一个用来指向一个或多个分片(shards)的“逻辑命名空间(logical namespace)”.
一个分片(shard)是一个最小级别“工作单元(worker unit)”,它只是保存索引中所有数据的一小片,分片是一个单一的Lucene实例
文档存储和被索引在分片中,程序不知道如何直接与分片通信,他们直接与索引通信

分片用于Elasticsearch在你的集群中分配数据。想象把分片当作数据的容器。文档存储在分片中,然后分片分配给你集群中的节点上。当你的集群扩容或缩小,Elasticsearch将会自动在你的节点间迁移分片,

以使集群保持平衡。
分片可以是主分片(primary shard)或者复制分片(replica shard)。
你索引中的每个文档属于一个单独的主分片,所以主分片的数量决定了你最多能存储多少数据。
复制分片只是主分片的一个副本,它用于提供数据的冗余副本,在硬件故障之后提供数据保护,同时服务于像搜索和检索等只读请求。

一个索引默认指派5个主分片,但是为了演示的目的,我们只指派3个主分片和一个复制分片(每个主分片有一个复制分片对应):

{
"settings" : {
    "number_of_shards"   : 3,
    "number_of_replicas" : 1
}
}


同一个节点上保存相同的数据副本是没有必要的,如果这个节点故障了,那所有的数据副本也会丢失
一些新的被索引的文档将首先被存储在主分片中,然后平行复制到关联的复制节点上。这可以确保我们的数据在主节点和复制节点上都可以被检索。

主分片的数量在创建索引时已经给定,复制分片的数量可以在运行中的集群中动态地变更,这允许我们可以根据需求扩大或者缩小规模

一个文档(行)不只有数据。它还包含了元数据(metadata)——关于文档的信息。三个必须的元数据节点是:
_index 文档存储的地方
_type 文档代表的对象的类
_id 文档的唯一标识
如下面的结构:
_index           _type          _id                          _score       id        name          funciton
------------------------------------------------------------------------
indexdemo123     typedemo123    AUxohiLEldvtLz1fv7mt          1           3         感冒灵颗粒     功能主治:解热镇痛。头痛 ,清热。
 _index,_type,_id,_score是自动加上去的(_score代表数据的相关度,猜测待验证),真正的业务数据只有id,name,function三列。

_index     、_type 、_id三者唯一确定一个文档

GET请求返回的响应内容包括{"found":true}。这意味着文档已经找到。如果我们请求一个不存在的文档,依旧会得到一个JSON,不过found值变成了false。
Elasticsearch中每个文档都有版本号,每当文档变化(包括删除)都会使 _version 增加
可以使用 upsert 参数定义文档来使其不存在时被创建

mget 允许我们一次性检索多个文档
 mget API参数是一个 docs  数组,数组的每个节点定义一个文档的 _index 、 _type  、 _id  元数据。如果你只想检索一个或几个确定的字段,也可以定义一个_source参数:

GET    /_mget
{
"docs"    : [
    {
        "_index":"website",
        "_type"    :"blog",
        "_id"    : 2
    },
    {
        "_index" : "website",
        "_type"    : "pageviews",
        "_id"    : 1,
        "_source": "views"
    }
    ]
}


响应体也包含一个 docs 数组,每个文档还包含一个响应,它们按照请求定义的顺序排列。每个这样的响应与单独使用 get request响应体相同:

bulk API允许我们使用单一请求来实现多个文档的create、index 、update或delete

POST    /_bulk
{ "delete": { "_index":    "website", "_type": "blog", "_id": "123" }}
{ "create": {    "_index":    "website",    "_type":    "blog",    "_id":    "123"    }}
{ "title": "My first blog post" }
{ "index": { "_index": "website", "_type": "blog" }}
{ "title": "My second blog post" }
{ "update": { "_index": "website", "_type": "blog", "_id": "123", "_retry_on_conflict" : 3} }
{ "doc"    : {"title" : "My updated blog    post"}}

Elasticsearch响应包含一个 items  数组,它罗列了每一个请求的结果,结果的顺序与我们请求的顺序相同

Elasticsearch使用一种叫做倒排索引(inverted index)的结构来做快速的全文搜索。倒排索引由在文档中出现的唯一的单词列表,以及对于每个单词在文档中的位置组成。
词(terms)或者表征(tokens)

查询子句就像是搭积木一样,可以合并简单的子句为一个复杂的查询语句,比如:
简单子句(leaf    clauses)(比如    match     子句)用以在将查询字符串与一个字段(或多字段)进行比较
复合子句(compound)用以合并其他的子句。例如, bool 子句允许你合并其他的合法子句,无论是must ,must_not 还是should,复合子句可以相互嵌套,从而实现非常复杂的逻辑

{
    "bool":    {
        "must":    {"match":{ "email":"business opportunity" }},
        "should":[
            { "match":{ "starred":    true }},
            { "bool": {
             "must":{"folder":"inbox" }},
             "must_not": { "spam": true }}
            }}
        ],
        "minimum_should_match":    1
    }
}


结构化查询(Query DSL)和结构化过滤(Filter    DSL)

--------------------------------------------------------------------------------------------------------------
最重要的查询过滤语句
term 过滤
 term 主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed 的字符串(未经分析的文本数据类型):

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


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

{
    "terms": {
        "tag":    [ "search", "full_text", "nosql" ]
        }
}


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

{
 "range": {
       "age": {"gte": 20,"lt":30}
      }
}

范围操作符包含:
    gt     ::    大于
    gte     ::    大于等于
    lt     ::    小于
    lte     ::    小于等于

exists和missing过滤:
 exists     和 missing 过滤可以用于查找文档中是否包含指定字段或没有某个字段,类似于SQL语句中的    IS_NULL     条件

{
    "exists":{
       "field": "title"
    }
}

这两个过滤只是针对已经查出一批数据来,但是想区分出某个字段是否存在的时候使用。

 bool 过滤
 bool 过滤可以用来合并多个过滤条件查询结果的布尔逻辑,它包含一下操作符:
 must :: 多个查询条件的完全匹配,相当于 and  。
 must_not :: 多个查询条件的相反匹配,相当于 not 。
 should  :: 至少有一个查询条件匹配, 相当于 or 。

这些参数可以分别继承一个过滤条件或者一个过滤条件的数组:

{
    "bool":    {
        "must":        {    "term":    {    "folder":    "inbox"    }},
        "must_not":    {    "term":    {    "tag":    "spam"        }},
        "should":    [
        {    "term":    {    "starred":    true}},
        {    "term":    {    "unread":        true}}
        ]
    }
}


match_all 查询
使用 match_all 可以查询到所有文档,是没有查询条件下的默认语句。

{
    "match_all":    {}
}

此查询常用于合并过滤条件。 比如说你需要检索所有的邮箱,所有的文档相关性都是相同的,所以得到的    _score 为1

match查询
 match 查询是一个标准查询,不管你需要全文本查询还是精确查询基本上都要用到它。
如果你使用 match 查询一个全文本字段,它会在真正查询之前用分析器先分析 match 一下查询字符:

{
    "match": {
        "tweet": "About    Search"
    }
}

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

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

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

不像我们在《简单搜索》中介绍的字符查询,    match     查询不可以用类似"+usid:2    +tweet:search"这样的语句。它只能就指定某个确切字段某个确切的值进行搜索,而你要做的就是为它指定正确的字段名以避免语法错误。

multi_match查询
multi_match查询允许你做    match 查询的基础上同时搜索多个字段:

{
    "multi_match":    {
        "query":    "full    text    search",
        "fields":[    "title",    "body"    ]
    }
}


bool查询与bool过滤相似,用于合并多个查询子句。不同的是,bool过滤可以直接给出是否匹配成功,而bool查询要计算每一个查询子句的_score(相关性分值)。
 must     :: 查询指定文档一定要被包含。
 must_not :: 查询指定文档一定不要被包含。
 should     :: 查询指定文档,有则可以为文档相关性加分。

以下查询将会找到title字段中包含    "how    to    make    millions",并且    "tag"    字段没有被标为spam。如果有标识为"starred"或者发布日期为2014年之前,
那么这些匹配的文档将比同类网站等级高:

{
    "bool":    {
        "must":        {"match":{"title":"how    to make    millions" }},
        "must_not":    {"match":{"tag":"spam"}},
        "should":    [
{    "match":    {"tag":    "starred"}},
{    "range":    {"date":{"gte":    "2014-01-01" }}}
        ]
    }
}

提示:    如果 bool 查询下没有 must 子句,那至少应该有一个 should 子句。但是 如果有 must 子句,那么没有 should 子句也可以进行查询。

node是es的运行实例,shard是一个单独的lucene实例
primary shard:  每个document都存储在一个单独的primary shard中。当为一个document建索引时,首先在primary shard上建立,然后在该primary shard的所有replica shards上面建。
replica shard: 每个primary shard有零或多个repica shard,replica是primary的拷贝,有两个目的,
 a) 提高恢复能力:当primary挂掉时,replica可以变成primary
 b) 提高性能:get和search请求既可以由primary又可以由replica处理
 默认的,每个primary有一个replica,但一个索引的replica的数量可以动态地调整。replica从不与它的primary在同一个node上启动。

routing: 当为某个document建立索引的时候,索引存储在某个primary shard上。该shard是通过哈希routing value选出来的。默认的,routing value通过document ID得到,或者当该文档有特定的父文档,从父文档的ID得到(这是为了保证子文档和父文档存储在相同的shard)。该value可以在建索引时指定,或者在mapping中通过routing field给定

Analyzer在Es中分为index_analyzer和search_analyzer
Index_analzyer:指的是索引过程中采用的分词器
Search_analyzer:指的是检索过程中采用的分词器

ES索引优化篇主要从两个方面解决问题,一是索引数据过程;二是检索过程。

posted on 2015-04-07 16:53  hi_rain  阅读(278)  评论(0)    收藏  举报