2.Elasticsearch基础使用

413 阅读9分钟

document数据格式

面向文档的搜索分析引擎

Elasticsearch 使用 JavaScript Object Notation(或者 JSON)作为文档的序列化格式。JSON 序列化为大多数编程语言所支持,并且已经成为 NoSQL 领域的标准格式。 它简单、简洁、易于阅读。

简单的集群管理

es提供了一套api,叫做cat api,可以查看es中各种各样的数据

GET /_cat/health?v

epoch      timestamp cluster       status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1606447321 03:22:01  elasticsearch yellow          1         1      7   7    0    0        1             0                  -                 87.5%

green:每个索引的primary shard和replica shard都是active状态的
yellow:每个索引的primary shard都是active状态的,但是部分replica shard不是active状态,处于不可用的状态
red:不是所有索引的primary shard都是active状态的,部分索引有数据丢失了
为什么现在会处于一个yellow状态?
我们现在就一个笔记本电脑,就启动了一个es进程,相当于就只有一个node。现在es中有一个index,就是kibana自己内置建立的index。由于默认的配置是给每个index分配5个primary shard和5个replica shard,而且primary shard和replica shard不能在同一台机器上(为了容错)。现在kibana自己建立的index是1个primary shard和1个replica shard。当前就一个node,所以只有1个primary shard被分配了和启动了,但是一个replica shard没有第二台机器去启动。
此时只要启动第二个es进程,就会在es集群中有2个node,然后那1个replica shard就会自动分配过去,然后cluster status就会变成green状态。

cat命令

/_cat/allocation      	#查看单节点的shard分配整体情况
/_cat/shards          #查看各shard的详细情况
/_cat/shards/{index}  	#查看指定分片的详细情况
/_cat/master          #查看master节点信息
/_cat/nodes           #查看所有节点信息
/_cat/indices         #查看集群中所有index的详细信息
/_cat/indices/{index} 	#查看集群中指定index的详细信息
/_cat/segments        #查看各index的segment详细信息,包括segment名, 所属shard, 内存(磁盘)占用大小, 是否刷盘
/_cat/segments/{index}#查看指定index的segment详细信息
/_cat/count           #查看当前集群的doc数量
/_cat/count/{index}   #查看指定索引的doc数量
/_cat/recovery        #查看集群内每个shard的recovery过程.调整replica。
/_cat/recovery/{index}#查看指定索引shard的recovery过程
/_cat/health          #查看集群当前状态:红、黄、绿
/_cat/pending_tasks   #查看当前集群的pending task
/_cat/aliases         #查看集群中所有alias信息,路由配置等
/_cat/aliases/{alias} #查看指定索引的alias信息
/_cat/thread_pool     #查看集群各节点内部不同类型的threadpool的统计信息,
/_cat/plugins         #查看集群各个节点上的plugin信息
/_cat/fielddata       #查看当前集群各个节点的fielddata内存使用情况
/_cat/fielddata/{fields}     #查看指定field的内存使用情况,里面传field属性对应的值
/_cat/nodeattrs              #查看单节点的自定义属性
/_cat/repositories           #输出集群中注册快照存储库
/_cat/templates              #输出当前正在存在的模板信息

简单CRUD操作

创建索引:PUT /test_index?pretty
查询索引:GET _cat/indices?v
删除索引:DELETE /test_index?pretty
v是带标题  pretty是美化输出

es会自动建立index和type,不需要提前创建,而且es默认会对document每个field都建立倒排索引,让其可以被搜索

添加数据:
PUT /phone/_doc/1
{
  "brand":"xiaomi",
  "price":1999,
  "title":"小米10 至尊纪念版",
  "tag":["双模5G","骁龙865","120HZ高刷新率","120倍长焦镜头","120W快充","NFC"]  
}
PUT /phone/_doc/2
{ 
  "brand":"vivo",
  "price":1099,
  "title":"vivo Y30",
  "tag":["智慧美颜","5G"]  
}
PUT /phone/_doc/3
{
  "brand":"huawei",
  "price":2999,
  "title":"华为 HUAWEI P40 Pro",
  "tag":["麒麟990","5000万超感知徕卡四摄","50倍数字变焦"]  
}
PUT /phone/_doc/4
{
  "brand":"apple",
  "price":3999,
  "title":"Apple iPhone 11",
  "tag":["4G","双卡双待"]  
}
检索数据:
GET /phone/_doc/1
替换文档:
PUT /phone/_doc/2
{ 
  "brand":"vivo",
  "price":1099,
  "title":"vivo Y30",
  "tag":["智慧美颜","5G"]  
}
替换方式有一个不好,即使必须带上所有的field,才能去进行信息的修改
修改文档:
POST /phone/_doc/2/_update
{ 
  "price":"1199", 
}
删除文档:
DELETE /phone/_doc/2

Elasticsearch搜索语法

timeout:
(1)设置:默认没有timeout,如果设置了timeout,那么会执行timeout机制。
(2)Timeout机制:假设用户查询结果有1W条数据,但是需要10″才能查询完毕,但是用户设置了1″的timeout,那么不管当前一共查询到了多少数据,都会在1″后ES讲停止查询,并返回当前数据。
(3)用法:GET /_search?timeout=1s/ms/m

1.query string search

query string search的由来,因为search参数都是以http请求的query string来附带的.
用于临时的在命令行使用一些工具,比如curl,快速的发出请求,来检索想要的信息;但是如果查询请求很复杂,是很难去构建的
在生产环境中,几乎很少使用query string search
查询所有:GET /phone/_search
带参数:GET /phone/_search?q=brand:xiaomi
分页:GET /phone/_search?from=0&size=2&sort=price:asc

2.DSL- 领域特定语言

Domain Specified Language,特定领域的语言
http request body:请求体,可以用json的格式来构建查询语法,比较方便,可以构建各种复杂的语法

//查询全部
GET /phone/_search
{
  "query": {
    "match_all": {}
  }
}
//按字段查询
GET /phone/_search
{
  "query": {
    "match": {
      "brand": "huawei"
    }
  }
}
// 按价格排序
GET /phone/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "price": {
        "order": "desc"
      }
    }
  ]
}
//多个字段查询一个关键词
GET /phone/_search
{
  "query": {
    "multi_match": {
      "query": "apple",
      "fields": ["brand","title"]
    }
  }
}
//_source 查询指定字段
GET /phone/_search
{
  "query": {
    "match_all": {}
  },
  "_source": ["title","price"]
}
//分页
GET /phone/_search
{
  "query": {
    "match_all": {}
  },
 "from": 2,
 "size": 4
}
//filter 过滤器
GET /phone/_search
{
  "query": {
   "bool": {
     "must": [
       {"match": {
         "brand": "apple"
       }}
     ],
     "filter": [
       {"range": {
         "price": {
           "gte": 3000,
           "lte": 4000
         }
       }}
     ]
   }
  }
}

3.full-text search(全文检索)

GET /phone/_search
{
  "query": {
    "match": {
      "title": "11"
    }
  }
}

GET /phone/_search
{
  "query": {
    "match": {
      "tag": "5G"
    }
  }
}

4.phrase search(短语搜索)

跟全文检索相对应,相反,全文检索会将输入的搜索串拆解开来,去倒排索引里面去一一匹配,只要能匹配上任意一个拆解后的单词,就可以作为结果返回
phrase search,要求输入的搜索串,必须在指定的字段文本中,完全包含一模一样的,才可以算匹配,才能作为结果返回

GET /phone/_search
{
  "query": {
    "match": {
      "title": "apple 11"
    }
  }
}

5.highlight search(高亮搜索结果)

GET /phone/_search
{
  "query": {
    "match": {
      "title": "apple"
    }
  },
  "highlight": {
    "fields": {"title": {}}
  }
}
返回结果:
{
  "took" : 135,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.3940738,
    "hits" : [
      {
        "_index" : "phone",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 1.3940738,
        "_source" : {
          "brand" : "apple",
          "price" : 3999,
          "title" : "Apple iPhone 11",
          "tag" : [
            "4G",
            "双卡双待"
          ]
        },
        "highlight" : {
          "title" : [
            "<em>Apple</em> iPhone 11"
          ]
        }
      }
    ]
  }
}

特殊

match和term查询的区别

match

  • match的查询词会被分词
  • match_phrase 不会分词
  • match_phrase 可对多个字段进行匹配 term
  • term代表完全匹配,不进行分词器分析
  • term 查询的字段需要在mapping的时候定义好,否则可能词被分词。传入指定的字符串,查不到数据

bool联合查询

Query and filter:查询和过滤

  • bool:可以组合多个查询条件,bool查询也是采用more_matches_is_better的机制,因此满足must和should子句的文档将会合并起来计算分值。
    1)must:必须满足
    子句(查询)必须出现在匹配的文档中,并将有助于得分。
    2)filter:过滤器 不计算相关度分数,cache☆
    子句(查询)必须出现在匹配的文档中。但是不像 must查询的分数将被忽略。Filter子句在filter上下文中执行,这意味着计分被忽略,并且子句被考虑用于缓存。
    3)should:可能满足 or
    子句(查询)应出现在匹配的文档中。
    4)must_not:必须不满足 不计算相关度分数 not
    子句(查询)不得出现在匹配的文档中。子句在过滤器上下文中执行,这意味着计分被忽略,并且子句被视为用于缓存。由于忽略计分,0因此将返回所有文档的分数。
    5)minimum_should_match
    参数指定should返回的文档必须匹配的子句的数量或百分比。如果bool查询包含至少一个should子句,而没有must或 filter子句,则默认值为1。否则,默认值为0

Deep paging

搜索过深的时候就需要在node上保存大量的数据,还要进行大量数据的排序,排序之后再取出对应的那一页,所以这个过程,既消耗网络宽带,耗费内存,还消耗cpu。这就是deep paging的性能问题,我们应该尽量避免出现这种deep paging操作。

elasticsearch提出了一个scroll滚动的方式,这个滚动的方式原理就是通过每次查询后,返回一个scroll_id。根据这个scroll_id 进行下一页的查询。可以把这个scroll_id理解为通常关系型数据库中的游标。但是,这种scroll方式的缺点是不能够进行反复查询,也就是说,只能进行下一页,不能进行上一页。

# 先查询第一页(这里的1m代表的是持续滚动时间,如果过了1分钟,还没有查询下一页,那么这个scroll_id就会失效)
GET /phone/_search?scroll=1m
{
  "query": {
    "match_all": {}
  },
  "size": 2
}

# 在根据scroll_id查询下一页
POST /_search/scroll
{
  "scroll": "1m",  
  "scroll_id":"FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFnZVX0YyNURsU3Z5eVNQWmY2cWc5VFEAAAAAAAAfwRZYNjJ6X0I0c1J2Q21OVzBJTXFxYWFR"
}

# 删除所有
DELETE /_search/scroll/_all
# 删除
DELETE /_search/scroll/{scroll_id}
  • 原理 -- 初始化时将所有符合搜索条件的搜索结果缓存起来,可以想象成快照
    -- 在遍历时,从这个快照里取数据
    -- 也就是说,在初始化后对索引插入、删除、更新数据都不会影响遍历结果
    游标可以增加性能的原因,是因为如果做深分页,每次搜索都必须重新排序,非常浪费,使用scroll就是一次把要用的数据都排完了,分批取出

filter 原理

聚合分析

Elasticsearch 有一个功能叫聚合(aggregations),允许我们基于数据生成一些精细的分析结果。聚合与 SQL 中的 GROUP BY 类似但更强大。

计算每个tag下的商品数量

// 将文本field的fielddata属性设置为true
PUT /phone
{
  "mappings": {
    "properties": {
      "tag":{
        "type": "text",
        "fielddata": true
      }
    }
  }
}
// 查询聚合语句
GET /phone/_search
{
  "aggs": {
    "all_tag": {
      "terms": {
        "field": "tag",
        "size": 100000
      }
    }
  }
}

对名称中包含xiaomi的商品,计算每个tag下的商品数量

GET /phone/_search
{
  "query": {
    "match": {
      "brand": "xiaomi"
    }
  }, 
  "aggs": {
    "all_tag": {
      "terms": {
        "field": "tag",
        "size": 100000
      }
    }
  }
}

先分组,再算每组的平均值,计算每个tag下的商品的平均价格

GET /phone/_search
{
  "aggs": {
    "all_tag": {
      "terms": {
        "field": "tag",
        "size": 100000
      },
      "aggs": {
        "all_avg": {
          "avg": {
            "field": "price"
          }
        }
      }
    }
  }
}

计算每个tag下的商品的平均价格,并且按照平均价格降序排序

GET /phone/_search
{
  "aggs": {
    "all_tag": {
      "terms": {
        "field": "tag",
        "order": {
          "all_avg": "desc"
        }, 
        "size": 100000
      },
      "aggs": {
        "all_avg": {
          "avg": {
            "field": "price"
          }
        }
      }
    }
  }
}

ElasticSearch完整目录

1. Elasticsearch是什么
2.Elasticsearch基础使用
3.Elasticsearch Mapping
4.Elasticsearch 集群原理
5.Elasticsearch Scripts和读写原理
6.Elasticsearch 分词器
7.Elasticsearch TF-IDF算法及高级查询
8.Elasticsearch 地理位置及搜索
9.Elasticsearch ELK