您当前的位置: 首页 >  ar

cuiyaonan2000

暂无认证

  • 0浏览

    0关注

    248博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Senior Course Of Elasticsearch

cuiyaonan2000 发布时间:2021-08-16 20:22:33 ,浏览量:0

序言

Elasticsearch是全文检索引擎的实现,之前的solr还没弄呢~又来个ES,太快。

Elastic 的底层是开源库 Lucene。但是,你没法直接用 Lucene,必须自己写代码去调用它的接口。

Elastic 是 Lucene 的封装,提供简单的RESTful API来隐藏Lucene的复杂性。

Elasticsearch和MongoDB/Redis/Memcache一样 本质上是一个非关系分布式型数据库,允许多台服务器协同工作。是一个接近实时的搜索平台,从索引这个文档到这个文档能够被搜索到只有一个轻微的延迟,企业应用的定位。

基本概念

与关系型数据库的对比如下

Relational DBElasticsearch数据库(database)索引(indices)表(tables)types行(rows)documents字段(columns)fields Node 与 Cluster

单个 Elastic 实例称为一个节点(node)。一组节点构成一个集群(cluster)。

Cluster模式支持一主多从且扩容简易,只要cluster.name一致且在同一个网络中就能自动加入当前集群cuiyaonan2000@163.com

Shards

Shards:代表索引分片,es可以把一个完整的索引分成多个分片,这样的好处是可以把一个大的索引拆分成多个,分布到不同的节点上。构成分布式搜索。分片的数量只能在索引创建前指定,并且索引创建后不能更改。

replicas

replicas代表索引副本,es可以设置多个索引的副本,副本的作用一是提高系统的容错性,当某个节点某个分片损坏或丢失时可以从副本中恢复。二是提高es的查询效率,es会自动对搜索请求进行负载均衡。

Recovery

代表数据恢复或叫数据重新分布,es在有节点加入或退出时会根据机器的负载对索引分片进行重新分配,挂掉的节点重新启动时也会进行数据恢复。---这里跟mongodb的分片很相似

Index(DataBase)

Elastic 会索引所有字段,经过处理后写入一个反向索引(Inverted Index)。查找数据的时候,直接查找该索引。------根据原始数据建立的,具有相关共性的索引集合。因为内容全是索引,故此就是一个索引数据库,对应关系型数据库中的Database。-----😒这里是ES的关键,其中还涉及到分词管理cuiyaonan2000@163.com

每个 Index (即数据库)的名字必须是小写。

下面的命令可以查看当前节点的所有 Index。

$ curl -X GET 'http://localhost:9200/_cat/indices?v'

Document(Row)

Index 里面单条的记录称为 Document(文档)。许多条 Document 构成了一个 Index。

Document 使用 JSON 格式表示,下面是一个例子。

同一个 Index 里面的 Document,不要求有相同的结构(scheme),但是最好保持相同,这样有利于提高搜索效率。

{
  "user": "cuiyaonan2000@163.com",
  "title": "工程师",
  "desc": "数据库管理"
}

Type(Group)

Document 可以分组,比如weather这个 Index 里面,可以按城市分组(北京和上海),也可以按气候分组(晴天和雨天)。这种分组就叫做 Type,它是虚拟的逻辑分组,用来过滤 Document。

不同的 Type 应该有相似的结构(schema),举例来说,id字段不能在这个组是字符串,在另一个组是数值。这是与关系型数据库的表的一个区别。性质完全不同的数据(比如productslogs)应该存成两个 Index,而不是一个 Index 里面的两个 Type(虽然可以做到)。

下面的命令可以列出每个 Index 所包含的 Type。

根据规划,Elastic 6.x 版只允许每个 Index 包含一个 Type,7.x 版将会彻底移除 Type。

$ curl 'localhost:9200/_mapping?pretty=true'

Field(列)

因为Document的schema可以不一样,所以不是所有的document都有相同的列。

RestFul Options

这里只是简单的一些操作,具体的请参照官网:Elasticsearch搜索API

全局操作 获取所有的索引
http://192.168.137.100:9200/_cat/indices?v

新建和删除 Index

新建 Index,可以直接向 Elastic 服务器发出 PUT 请求。下面的例子是新建一个名叫weather的 Index。index的名字必须是小写

$ curl -X PUT 'localhost:9200/weather'

服务器返回一个 JSON 对象,里面的acknowledged字段表示操作成功。


{
  "acknowledged":true,
  "shards_acknowledged":true
}

然后,我们发出 DELETE 请求,删除这个 Index。

$ curl -X DELETE 'localhost:9200/weather'

中文分词设置

首先,安装中文分词插件。这里使用的是 ik,也可以考虑其他插件(比如 smartcn)。

中文分词其实只是一个选择,告诉ES我们该用哪个插件,具体分词操作不是我们这边做cuiyaonan2000@163.com


$ ./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v5.5.1/elasticsearch-analysis-ik-5.5.1.zip

上面代码安装的是5.5.1版的插件,与 Elastic 5.5.1 配合使用。-----注意版本兼容性的问题

接着,重新启动 Elastic,就会自动加载这个新安装的插件。

然后,新建一个 Index,指定需要分词的字段。这一步根据数据结构而异,下面的命令只针对本文。基本上,凡是需要搜索的中文字段,都要单独设置一下。


$ curl -X PUT 'localhost:9200/accounts' -d '
{
  "mappings": {
    "person": {
      "properties": {
        "user": {
          "type": "text",
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_max_word"
        },
        "title": {
          "type": "text",
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_max_word"
        },
        "desc": {
          "type": "text",
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_max_word"
        }
      }
    }
  }
}'

上面代码中,首先新建一个名称为accounts的 Index,里面有一个名称为person的 Type。person有三个字段。

  1. user
  2. title
  3. desc

这三个字段都是中文,而且类型都是文本(text),所以需要指定中文分词器,不能使用默认的英文分词器。-----同时说明了只有当我们的字段是类型是text的时候才会用到分词器cuiyaonan2000@163.com

Elastic 的分词器称为 analyzer。我们对每个字段指定分词器

  1. analyzer是字段文本的分词器,
  2. search_analyzer是搜索词的分词器
  3. ik_max_word分词器是插件ik提供的,可以对文本进行最大数量的分词。

新增Document

向指定的 /Index/Type 发送 PUT 请求,就可以在 Index 里面新增一条记录。比如,向/accounts/person发送请求,就可以新增一条人员记录。

$ curl -X PUT 'localhost:9200/accounts/person/1' -d '
{
  "user": "张三",
  "title": "工程师",
  "desc": "数据库管理"
}' 

服务器返回的 JSON 对象,会给出 Index、Type、Id、Version 等信息。


{
  "_index":"accounts",
  "_type":"person",
  "_id":"1",
  "_version":1,
  "result":"created",
  "_shards":{"total":2,"successful":1,"failed":0},
  "created":true
}

如果你仔细看,会发现请求路径是/accounts/person/1,最后的1是该条记录的 Id。它不一定是数字,任意字符串(比如abc)都可以。

新增记录的时候,也可以不指定 Id,这时要改成 POST 请求。

$ curl -X POST 'localhost:9200/accounts/person' -d '
{
  "user": "李四",
  "title": "工程师",
  "desc": "系统管理"
}'

上面代码中,向/accounts/person发出一个 POST 请求,添加一个记录。这时,服务器返回的 JSON 对象里面,_id字段就是一个随机字符串。

{
  "_index":"accounts",
  "_type":"person",
  "_id":"AV3qGfrC6jMbsbXb6k1p",
  "_version":1,
  "result":"created",
  "_shards":{"total":2,"successful":1,"failed":0},
  "created":true
}

注意:如果没有事先建立index ,ES也不会报错,同时会自动创建,所以要注意大小写。

查询Document

/Index/Type/Id发出 GET 请求,就可以查看这条记录。

$ curl 'localhost:9200/accounts/person/1?pretty=true'

上面代码请求查看/accounts/person/1这条记录,URL 的参数pretty=true表示以易读的格式返回。

返回的数据中,found字段表示查询成功,_source字段返回原始记录。


{
  "_index" : "accounts",
  "_type" : "person",
  "_id" : "1",
  "_version" : 1,
  "found" : true,
  "_source" : {
    "user" : "张三",
    "title" : "工程师",
    "desc" : "数据库管理"
  }
}

如果 Id 不正确,就查不到数据,found字段就是false


$ curl 'localhost:9200/weather/beijing/abc?pretty=true'

{
  "_index" : "accounts",
  "_type" : "person",
  "_id" : "abc",
  "found" : false
}

删除Document

删除记录就是发出 DELETE 请求。

$ curl -X DELETE 'localhost:9200/accounts/person/1'

更新Document

更新记录就是使用 PUT 请求,重新发送一次数据。

$ curl -X PUT 'localhost:9200/accounts/person/1' -d '
{
    "user" : "张三",
    "title" : "工程师",
    "desc" : "数据库管理,软件开发"
}' 

//返回JSON
{
  "_index":"accounts",
  "_type":"person",
  "_id":"1",
  "_version":2,
  "result":"updated",
  "_shards":{"total":2,"successful":1,"failed":0},
  "created":false
}

可以看到,记录的 Id 没变,但是版本(version)从1变成2,操作类型(result)从created变成updatedcreated字段变成false,因为这次不是新建记录。

查询Document

返回所有记录

使用 GET 方法,直接请求/Index/Type/_search,就会返回所有记录。

$ curl 'localhost:9200/accounts/person/_search'

{
  "took":2,
  "timed_out":false,
  "_shards":{"total":5,"successful":5,"failed":0},
  "hits":{
    "total":2,
    "max_score":1.0,
    "hits":[
      {
        "_index":"accounts",
        "_type":"person",
        "_id":"AV3qGfrC6jMbsbXb6k1p",
        "_score":1.0,
        "_source": {
          "user": "李四",
          "title": "工程师",
          "desc": "系统管理"
        }
      },
      {
        "_index":"accounts",
        "_type":"person",
        "_id":"1",
        "_score":1.0,
        "_source": {
          "user" : "张三",
          "title" : "工程师",
          "desc" : "数据库管理,软件开发"
        }
      }
    ]
  }
}

  • total:返回记录数,本例是2条。
  • max_score:最高的匹配程度,本例是1.0
  • hits:返回的记录组成的数组。
  • took:该次操作所耗费的毫秒数
  • time_out: 该次操作是否超时
  • _source: 表示匹配的程序,默认是按照这个字段降序排列。

条件查询

$ curl 'localhost:9200/accounts/person/_search'  -d '
{
  "query" : { "match" : { "desc" : "软件" }}
}'

上面代码使用 Match 查询,指定的匹配条件是desc字段里面包含"软件"这个词。返回结果如下。

{
  "took":3,
  "timed_out":false,
  "_shards":{"total":5,"successful":5,"failed":0},
  "hits":{
    "total":1,
    "max_score":0.28582606,
    "hits":[
      {
        "_index":"accounts",
        "_type":"person",
        "_id":"1",
        "_score":0.28582606,
        "_source": {
          "user" : "张三",
          "title" : "工程师",
          "desc" : "数据库管理,软件开发"
        }
      }
    ]
  }
}

Elastic 默认一次返回10条结果,可以通过size字段改变这个设置。

$ curl 'localhost:9200/accounts/person/_search'  -d '
{
  "query" : { "match" : { "desc" : "管理" }},
  "size": 1
}'

上面代码指定,每次只返回一条结果。

还可以通过from字段,指定位移。--跟Mysql的Offset一样


$ curl 'localhost:9200/accounts/person/_search'  -d '
{
  "query" : { "match" : { "desc" : "管理" }},
  "from": 1,
  "size": 1
}'

逻辑条件查询

如果有多个搜索关键字, Elastic 认为它们是or关系。

$ curl 'localhost:9200/accounts/person/_search'  -d '
{
  "query" : { "match" : { "desc" : "软件 系统" }}
}'

上面代码搜索的是软件 or 系统

如果要执行多个关键词的and搜索,必须使用布尔查询。

$ curl 'localhost:9200/accounts/person/_search'  -d '
{
  "query": {
    "bool": {
      "must": [
        { "match": { "desc": "软件" } },
        { "match": { "desc": "系统" } }
      ]
    }
  }
}'

搜索

搜索的格式是:     //_search   其中 index和type是可选的,搜索的范围如下:

  • http://localhost:9200/_search - 搜索所有索引和所有类型。---没有index和type
  • http://localhost:9200/movies/_search - 在电影索引中搜索所有类型  ----有index
  • http://localhost:9200/movies/movie/_search - 在电影索引中显式搜索电影类型的文档。 ----有index和type

那Elasticsearch的DSL格式如下:

curl -XPOST "http://localhost:9200/_search" -d'
{
    "query": {   ----query是关键字
        "query_string": {           ---query_string是es提供的查询类型
            "query": "kill"
        }
    }
}'

如上所示Elasticsearch的格式首先必须有query,然后是个query_type(这是es提供的查询类型,或者叫对象,里面有很多参数,用于我们查询cuiyaonan2000@163.com)

如上query_string 只设置一个属性即 "query": "kill"  所以它会把所有记录中的任意字段包含kill的记录返回.

如果在明确一点,可以设置 query_string中的filed字段来限制记录中的哪个字段是否满足条件.

curl -XPOST "http://localhost:9200/_search" -d'
{
    "query": {
        "query_string": {
            "query": "ford",
            "fields": ["title"]
        }
    }
}'

过滤

这个过滤器的目的我在想可能是用于复杂的查询???? 

因为过滤器  = 查询+过滤 即 先查询出满足条件的记录,然后在根据一些条件进行过滤.

如下可以看到 过滤器(filtered) 其实是query另一个query_type,然后它包含了2个属性queyr和filter.

curl -XPOST "http://localhost:9200/_search" -d'
{
    "query": {
        "filtered": {
            "query": {
                "query_string": {
                    "query": "drama"
                }
            },
            "filter": {
                "term": { "year": 1962 }
            }
        }
    }
}'


//如下的格式是将所有满足的记录都进行过滤
curl -XPOST "http://localhost:9200/_search" -d'
{
    "query": {
        "filtered": {
            "query": {
                "match_all": {
                }
            },
            "filter": {
                "term": { "year": 1962 }
            }
        }
    }
}'

聚合

聚合与搜索我觉得挺好理解. 聚合就是针对我们的搜索内容进行计算cuiyaonan2000@163.com

聚合= 搜索/过滤 + 分析

那聚合内部是如何进行 数据分析的呢? 聚合的两个主要的概念,分别是 桶 和 指标

桶(Buckets) : 满足特定条件的文档的结果集合

桶可以被嵌套在其他桶里面

像是一个员工属于男性桶或者女性桶,日期2014-10-28属于十月桶,也属于2014年桶

像是北京能放在中国桶裡,而中国桶能放在亚洲桶裡

Elasticsearch提供了很多种类型的桶,像是时间、最受欢迎的词、年龄区间、地理位置桶等等

指标(Metrics) : 对桶内的文档进行统计计算

指标通常是简单的数学运算(像是min、max、avg、sum),而这些是通过当前桶中的文档的值来计算的,利用指标能让你计算像平均薪资、最高出售价格、95%的查询延迟这样的数据

aggs 聚合的模板

aggs的官方标准格式为

"aggregations" : {
   "" : {     //聚合的名称
      "" : {   // 桶的名称,es默认提供了很多请注意cuiyaonan2000@163.com
              //字段参数等
      }

      [,"meta" : { [] } ]?
      [,"aggregations" : { []+ } ]?
   }
}

另外需要注意的一些内容:

  1. 当query和aggs一起存在时,会先执行query的主查询,主查询query执行完后会搜出一批结果,而这些结果才会被拿去aggs拿去做聚合
  2. 一个aggs裡可以有很多个聚合,每个聚合彼此间都是独立的,因此可以一个聚合拿来统计数量、一个聚合拿来分析数据、一个聚合拿来计算标准差...,让一次搜索就可以把想要做的事情一次做完
  3. 如果有些情况不在意查询结果是什麽,而只在意aggs的结果,可以把size设为0,如此可以让返回的hits结果集是0,加快返回的速度-------值得query层的size设置成0哦cuiyaonan2000@163.com
  4. aggs可以嵌套在其他的aggs裡面,而嵌套的桶能作用的文档集范围,是外层的桶所输出的结果集

聚合--常用桶

terms---类似于group by

模拟一个索引只有1个字段,包含如下内容

  1. { "color": "red" }

  2. { "color": "green" }

  3. { "color": ["red", "blue"] }


GET 127.0.0.1/mytest/doc/_search
{
	"query": {
		"match_all": {}
	},

	"size": 0,  //这里的0标识query查询的内容不用返回.我们只要聚合的返回,这样提升速度

	"aggs": {

		"my_name": {

			"terms": {

				"field": "color"
			}
		}
	}
}

返回结果

{
    "took": 0,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 1,
        "max_score": 0.0,
        "hits": []
    },

    //这里是聚合的返回结果
    "aggregations ": {
	"my_name": {
		"doc_count_error_upper_bound": 0,
		"sum_other_doc_count": 0,
		"buckets": [
			{
				"key": "blue",
				"doc_count": 1
			},
			{
				"key": "red",
				"doc_count": 2 //为2的原因你猜测下
			},
			{
				"key": "green",
				"doc_count": 1
			}
		]
	}
}

嵌套聚合
  1. { "color": "red", "price": 100 }

  2. { "color": "green", "price": 500 }

  3. { "color": ["red", "blue"], "price": 1000 }

如下my_name桶下首先根据color分组,然后在计算该组中的平均价格和最小价格cuiyaonan2000@163.com

{
    "query":{
        "match_all":{

        }
    },
    "size":0,
    "aggs":{
        "my_name":{
            "terms":{
                "field":"color"
            },
            "aggs":{     //这里就是嵌套聚合, aggs是关键字
                "my_avg_price":{     //桶的名称
                    "avg":{            //聚合分类
                        "field":"price"
                    }
                },
                "my_min_price":{
                    "min":{
                        "field":"price"
                    }
                }
            }
        }
    }
}

批量处理

批量处理不仅仅支持批量插入,删除,更新,创建索引等操作都支持.

  1. delete 删除操作,只需要写一个json即可
  2. create 创建操作,如果需要创建的文档已经存在,那么创建失败
  3. index 创建或替换操作,如果要创建的文档不存在则执行创建操作,如果已经存在则执行替换操作
  4. update 更新操作  执行文档的更新
POST http://path.to.your.cluster/_bulk

向指定的 /Index/Type 发送 PUT 请求,就可以在 Index 里面新增一条记录。比如,向/accounts/person发送请求,就可以新增一条人员记录。


第一行指定请求与索引和类型,可以选择的请求有"create",“index”,“delete”,“ubdate”,“_index"指定索引名,”_type"指定类型名,"_id"指定id
{ "index":{ "_index": "myIndex", "_type": "person" } }
{ "name":"john doe","age":25 }


{ "index":{ "_index": "myOtherIndex", "_type": "dog" } }
{ "name":"fido","breed":"chihuahua" }


除了索引名和类型外,还可以在批量插入请求中为每个文档提供id:
{ "index":{ "_id": "8a78dhkujg" } }
{ "name":"mary smith","age":32 }

关注
打赏
1638267374
查看更多评论
立即登录/注册

微信扫码登录

0.0406s