#### ES散记 ####

一、第一部分

中文分词器

首先我们来了解一下中文分词器,中文分词器有两种:一种是ik_max_word,一种是ik_smart,我们分别来看下他们对中文分词的拆分

ik_max_word分词器

采用ik_max_word分词器,我们看到我是中国人分成了:我、是、中国人、中国、国人

ik_smart分词器

下面我们采用ik_smart来进行分词,同样还是对“我是中国人”这句话来进行分词,我们可以看到,采用ik_smart分词器分成了:我、是、中国人

我们发现,ik_max_word是一种细粒度的拆分,而ik_smart则是一种较为智能的拆分,实际使用时可根据不同场景来进行选择

Rest风格

我们知道,elasticsearch是一套基于Rest风格的api,我们刚刚是在Kibana可视化控制台中进行的请求操作,同样的,我们可以借助postman等工具对其发起rest风格的请求,如下,也得到了我们想要的结果,所以它的使用方式是很灵活的

不过在Kibana中有很强大的语法提示,使用起来更加灵活,它的底层实现还是rest请求,只不过帮我们都封装好了

elasticsearch的一些概念

索引(indices):

数据库databases

类型(type):

Table数据表

文档(Document):

Row行,每一行数据就是一个文档,类似mysql查询出来的每一行数据

字段(Field):

Columns列,类似mysql的每个字段

索引库

创建索引库类似于创建数据库,我们创建一个名为test的数据库,语法:

PUT /test

{

  "settings": {

    "number_of_shards": 5

    , "number_of_replicas": 1

  }

}

查询索引库

GET /test

删除索引库

DELETE /test

创建映射字段

在test数据库下面创建一张商品表,商品表里面有3个字段,分别是title、images、price

创建语法:

PUT /test/_mapping/goods

{

  "properties": {

    "title":{

      "type": "text",

      "analyzer": "ik_max_word"

    },

    "images":{

      "type": "keyword",

      "index": false

    },

    "price":{

      "type": "float"

    }

  }

}

我们通过上面的语法,发现几个关键词,首先类型,文本类型有text和keyword,它们有什么区别呢,text类型的文本可以用来分词,不可用来聚合,而keyword的类型的文本不可分词,数据会作为完整的字段进行匹配,可以参与聚合

index代表是否索引,默认值为true,而一般图片的地址不需要检索的,所以index给设置为false

查看映射关系

GET /test/_mapping/goods

elasticsearch字段类型概述

一级分类 二级分类 具体类型

核心类型 字符串类型 text,keyword

整数类型 integer,long,short,byte

浮点类型 double,float,half_float,scaled_float

逻辑类型 boolean

日期类型 date

范围类型 range

二进制类型 binary

复合类型 数组类型 array

对象类型 object

嵌套类型 nested

地理类型 地理坐标类型 geo_point

地理地图 geo_shape

特殊类型 IP类型 ip

范围类型 completion

令牌计数类型 token_count

附件类型 attachment

抽取类型 percolator

添加数据

添加一条数据:

POST /test/goods

{

  "title":"小米手机",

  "images":"http://img.xiaomi.com",

   "price":2999.5

}

查询所有数据:

GET /test/_search

{

  "query": {

    "match_all": {}

  }

}

根据id查询数据:

GET /test/goods/HHzUuWkB96yUdC__j7MfGET

修改数据

根据id修改数据:

PUT /test/goods/HHzUuWkB96yUdC__j7Mf

{

   "title" : "中米手机",

   "images" : "http://img.xiaomi.com",

   "price" : 3999

}

put功能很强大,如果id不存在,则是新增数据

PUT /test/goods/123565

{

   "title" : "锤子手机",

   "images" : "http://img.chuizi.com",

   "price" : 1888

}

我们可以看到,result的返回结果,如果是修改数据,返回的updated,如果是新增数据,返回的是created,很灵活,可以代替post添加数据的功能

删除数据

根据id删除数据:

DELETE /test/goods/HHzUuWkB96yUdC__j7Mf

match查询

我们现在检索小米手机

GET /test/_search

{

  "query": {

     "match": {

       "title": "小米手机"

     }

  }

}

但是我们仔细看结果,咦?为什么华为手机,锤子手机都搜索出来了,这里注意了,我们存储的时候需要分词,搜索的时候也需要分词,我们虽然是搜索小米手机,实际上elasticsearch是拿着小米、手机这两个词去库里面检索的。所以有小米或者手机这两个词的都被检索出来了

那我们就想搜索小米手机怎么办呢?我们可以采用下面的方式(用and关系,operator指定为and)

GET /test/_search

{

  "query": {

    "match": {

      "title": {"query": "小米手机","operator": "and"}

    }

  }

}

match_all查询

查询所有数据,这个前面接演示过,这里不再赘述了,语法格式如下:

GET /test/_search

{

  "query": {

    "match_all": {}

  }

}

词条查询

我们用term来查询小米手机

GET /test/_search

{

  "query": {

    "term": {

      "title": {

        "value": "小米手机"

      }

    }

  }

}

我们发现,词条查询居然查不出小米手机,这是为什么呢?这是因为词条查询是将小米手机作为一个整体去数据库里面查询,而数据库里面的title字段都是分过词的,拿着整体去匹配分过词的数据,当然是查询不到啦!所以词条查询一般应用场景是用来去查询那些不分词的字段,例如:价格,图片地址

指定返回字段

有的时候,我们可能不需要所有的字段都返回,那我们可以用source来指定需要返回的具体字段

GET /test/_search

{

  "_source": ["title","price"],

  "query": {

    "match": {

      "title": "小米手机"

    }

  }

}

还有另外两种变种写法:

写法一(includes包含需要返回的字段):

GET /test/_search

{

  "_source": {

    "includes": ["title","price"]

  },

  "query": {

    "match": {

      "title": "小米手机"

    }

  }

}

写法二(excludes排除需要返回的字段):

GET /test/_search

{

  "_source": {

    "excludes": ["title","price"]

  },

  "query": {

    "match": {

      "title": "小米手机"

    }

  }

}

模糊查询

有一个场景,用户想搜索apple手机,但是不小心输入成applo,怎么办呢?别急,模糊查询fuzzy派上用场啦!

GET /test/_search

{

  "query": {

    "fuzzy": {

      "title": "applo"

    }

  }

}

我们看到了,即使用户输错了,我们仍然可以查询出来

指定范围查询

查询价格在3000-5000范围内的手机:

GET /test/_search

{

  "query": {

    "range": {

      "price": {

        "gte": 3000,

        "lte": 5000

      }

    }

  }

}

布尔查询

查询商品名为小米手机,同时价格在1000-5000范围内的商品

GET /test/_search

{

  "query": {

    "bool": {

      "must": [

        {"match": {

          "title": {"query": "小米手机","operator": "and"}

        }}

      ],

      "filter": {

        "range": {

          "price": {

            "gte": 1000,

            "lte": 5000

          }

        }

      }

    }

  }

}

排序

查询商品名称为手机的商品并按照价格升序排序:

GET /test/_search

{

  "query": {

    "match": {

      "title":{"query": "手机"}

    }

  },

  "sort": [

    {

      "price": {

        "order": "desc"

      }

    }

  ]

}

二、第二部分

es概念:

一个索引就是一个db,一个索引可有多张表,type相当于表

字段结构即mapping,支持新增,不支持删除和修改

一条记录头部有id,可以在插入时指定,也可以插入时生成

条的数据信息存在source里

docker安装es、kabana、ik分词

docker search elasticsearch

docker pull nshou/elasticsearch-kibana

docker images

docker run -d -p 9200:9200 -p 5601:5601 nshou/elasticsearch-kibana --name eskb

在线安装ik

docker exec -it es /bin/bash

./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.7.0/elasticsearch-analysis-ik-7.7.0.zip

注意版本和对应es,安装好后会在plugi下生成文件

es命令

http://172.16.1.23:9200/_cat/indices?v

显示全部数据

http://172.16.1.23:9200/svc_search_mp_group/_search

检索

http://172.16.1.23:9200/svc_search_mp_group/_doc/_search/?q=group_name:分组

http://172.16.1.23:9200/svc_search_mp_content/_search/?q=pt_type:1

http://172.16.1.23:9200/svc_search_mp_content/_search/?q=id:515

查看索引结构

http://172.16.1.23:9200/svc_search_oplog/_mapping/

增加索引字段

PUT http://172.16.1.23:9200/svc_search_oplog/_mapping

{

"properties": {

"op_detail": {

"type": "text",

"analyzer": "my_ik_max_word",

"search_analyzer": "my_ik_smart"

}

}

}

修改文档名

https://www.jianshu.com/p/b1c7be021d9e

在 Elasticsearch 中文档是 不可改变 的,不能修改它们。在我们对文档进行更新操作的时候,都会将旧文档删除,在原来的位置创建新的文档.

我们会发现"_version"字段变成了2,这是因为这个字段标志着版本号,表示这是在这个index,这个type,这个id下,第二次存储的数据.

执行:

POST svc_search_mp_apply/_doc/15192491366042977927/_update

{

"doc" : {

"mp_name" : "test"

}

}

返回:

#! Deprecation: [types removal] Specifying types in document update requests is deprecated, use the endpoint /{index}/_update/{id} instead.

{

"_index" : "svc_search_mp_apply",

"_type" : "_doc",

"_id" : "15192491366042977927",

"_version" : 2,

"result" : "noop",

"_shards" : {

"total" : 0,

"successful" : 0,

"failed" : 0

},

"_seq_no" : 11,

"_primary_term" : 4

}

独立安装kibana(推荐使用es+kbn的镜像组合)

安装:brew install kibana

启动:kibana

浏览器访问:http://localhost:5601

连接es:

kibana 配置文件位置:

brew install安装应用最先是放在/usr/local/Cellar/目录下

cd到kibana,里面的config -> /usr/local/etc/kibana

修改:(取消默认的注释那几项即可)

server.port: 5601

server.host: "0.0.0.0"

elasticsearch.url: "http://192.168.202.128:9200"

kibana.index: ".kibana"

kbn命令

全部索引:

GET _cat/indices

svc_search_oplog信息:

GET svc_search_oplog

svc_search_oplog的setting信息:

GET svc_search_oplog/_settings

svc_search_oplog的mapping信息:

GET svc_search_oplog/_mapping

新建索引mappings svc_search_oplog:

PUT svc_search_oplog

{

"mappings": {

"properties": {

"account_id": {

"type": "keyword"

},

"account_sign": {

"analyzer": "my_ik_max_word",

"search_analyzer": "my_ik_smart",

"type": "text"

},

"created_at": {

"type": "long"

},

"op_detail": {

"analyzer": "my_ik_max_word",

"search_analyzer": "my_ik_smart",

"type": "text"

},

"op_log_id": {

"type": "keyword"

},

"op_object": {

"type": "keyword"

}

}

},

"settings": {

"analysis": {

"analyzer": {

"my_ik_max_word": {

"char_filter": [

"html_strip"

],

"tokenizer": "ik_max_word",

"type": "custom"

},

"my_ik_smart": {

"char_filter": [

"html_strip"

],

"tokenizer": "ik_smart",

"type": "custom"

}

}

}

}

}

插入条:

#指定索引为lagou,表为job,id为1

PUT lagou/job/1

{

"title":"后端研发",

"salary_min":20000,

"Company":{

"name":"百度",

"address":"北京"

}

}

获取条:

#获取索引为lagou,表为job,id为1的数据

GET lagou/job/1

修改条:

#直接覆盖id为1的文档

PUT lagou/job/1

{

"title":"后端研发",

"salary_min":10000,

"Company":{

"name":"百度",

"address":"北京"

}

}

#指明字段修改,doc为固定格式,指明要修改的字段

POST lagou/job/1/_update

{

"doc":

{

"salary_min":20000

}

}

删除索引为lagou,表为job,id为1的数据:

DELETE lagou/job/1

删除索引,不支持删除表:

DELETE lagou

获取svc_search_oplog的全部数据:

GET /svc_search_oplog/_search

{

"query": {

"match_all": {}

}

}

参数大致解释:

took: 执行搜索耗时,毫秒为单位

time_out: 搜索是否超时

_shards: 多少分片被搜索,成功多少,失败多少

hits: 搜索结果展示

hits.total: 匹配条件的文档总数

hits.hits: 返回结果展示,默认返回十个

hits.max_score:最大匹配得分

hits._score: 返回文档的匹配得分(得分越高,匹配程度越高,越靠前)

_index _type _id 作为剥层定位到特定的文档

_source 文档源

———————————————————————————————————————————

https://www.cnblogs.com/yjf512/p/4897294.html

https://blog.csdn.net/qq_24365213/article/details/79224630

———————————————————————————————————————————

elasticsearch 查询(match和term)

es中的查询请求有两种方式,一种是简易版的查询,另外一种是使用JSON完整的请求体,叫做结构化查询(DSL)。

由于DSL查询更为直观也更为简易,所以大都使用这种方式。

DSL查询是POST过去一个json,由于post的请求是json格式的,所以存在很多灵活性,也有很多形式。

这里有一个地方注意的是官方文档里面给的例子的json结构只是一部分,并不是可以直接黏贴复制进去使用的。一般要在外面加个query为key的机构。

match

最简单的一个match例子:

查询和"我的宝马多少马力"这个查询语句匹配的文档。

{

"query": {

"match": {

"content" : {

"query" : "我的宝马多少马力"

}

}

}

}

上面的查询匹配就会进行分词,比如"宝马多少马力"会被分词为"宝马 多少 马力", 所有有关"宝马 多少 马力", 那么所有包含这三个词中的一个或多个的文档就会被搜索出来。

并且根据lucene的评分机制(TF/IDF)来进行评分。

match_phrase

比如上面一个例子,一个文档"我的保时捷马力不错"也会被搜索出来,那么想要精确匹配所有同时包含"宝马 多少 马力"的文档怎么做?就要使用 match_phrase 了

{

"query": {

"match_phrase": {

"content" : {

"query" : "我的宝马多少马力"

}

}

}

}

完全匹配可能比较严,我们会希望有个可调节因子,少匹配一个也满足,那就需要使用到slop。

{

"query": {

"match_phrase": {

"content" : {

"query" : "我的宝马多少马力",

"slop" : 1

}

}

}

}

multi_match

如果我们希望两个字段进行匹配,其中一个字段有这个文档就满足的话,使用multi_match

{

"query": {

"multi_match": {

"query" : "我的宝马多少马力",

"fields" : ["title", "content"]

}

}

}

但是multi_match就涉及到匹配评分的问题了。

best_fields

我们希望完全匹配的文档占的评分比较高,则需要使用best_fields

{

"query": {

"multi_match": {

"query": "我的宝马发动机多少",

"type": "best_fields",

"fields": [

"tag",

"content"

],

"tie_breaker": 0.3

}

}

}

意思就是完全匹配"宝马 发动机"的文档评分会比较靠前,如果只匹配宝马的文档评分乘以0.3的系数

most_fields

我们希望越多字段匹配的文档评分越高,就要使用

{

"query": {

"multi_match": {

"query": "我的宝马发动机多少",

"type": "most_fields",

"fields": [

"tag",

"content"

]

}

}

}

cross_fields

我们会希望这个词条的分词词汇是分配到不同字段中的,那么就使用

{

"query": {

"multi_match": {

"query": "我的宝马发动机多少",

"type": "cross_fields",

"fields": [

"tag",

"content"

]

}

}

}

term

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

{

"query": {

"term": {

"content": "汽车保养"

}

}

}

查出的所有文档都包含"汽车保养"这个词组的词汇。

使用term要确定的是这个字段是否“被分析”(analyzed),默认的字符串是被分析的。

拿官网上的例子举例:

mapping是这样的:

PUT my_index

{

"mappings": {

"my_type": {

"properties": {

"full_text": {

"type": "string"

},

"exact_value": {

"type": "string",

"index": "not_analyzed"

}

}

}

}

}

PUT my_index/my_type/1

{

"full_text": "Quick Foxes!",

"exact_value": "Quick Foxes!"

}

其中的full_text是被分析过的,所以full_text的索引中存的就是[quick, foxes],而extra_value中存的是[Quick Foxes!]。

那下面的几个请求:

GET my_index/my_type/_search

{

"query": {

"term": {

"exact_value": "Quick Foxes!"

}

}

}

请求的出数据,因为完全匹配

GET my_index/my_type/_search

{

"query": {

"term": {

"full_text": "Quick Foxes!"

}

}

}

请求不出数据的,因为full_text分词后的结果中没有[Quick Foxes!]这个分词。

bool联合查询: must,should,must_not

如果我们想要请求"content中带宝马,但是tag中不带宝马"这样类似的需求,就需要用到bool联合查询。

联合查询就会使用到must,should,must_not三种关键词。

这三个可以这么理解

must: 文档必须完全匹配条件

# filter:过滤,不参与打分

should: should下面会带一个以上的条件,至少满足一个条件,这个文档就符合should

must_not: 文档必须不匹配条件

比如上面那个需求:

{

"query": {

"bool": {

"must": {

"term": {

"content": "宝马"

}

},

"must_not": {

"term": {

"tags": "宝马"

}

}

}

}

}

———————————————————————————————————————————

使用多种分词器

https://www.jianshu.com/p/c47cd5313653

如果希望使用多种分析器得到不同的分词,可以使用 multi-fields 特性,指定多个产生字段:

PUT /my-index/_mapping/my-type

{

"my-type": {

"properties": {

"name": {

"type": "string",

"analyzer": "standard",

"fields": {

"custom1": {

"type": "string",

"analyzer": "custom1"

},

"custom2": {

"type": "string",

"analyzer": "custom2"

}

}

}

}

}

}

这样你可以通过 name、name.custom1、name.custom2 来使用不同的分析器得到的分词。

查询时也可以指定分析器

如:

POST /my-index/my-type/_search

{

"query": {

"match": {

"name": {

"query": "it's brown",

"analyzer": "standard"

}

}

}

}

———————————————————————————————————————————

##### 区别:term、match、match phrase、match phrase prefix

term

匹配一个值,输入的值不会分词。

match

模糊匹配,先对输入进行分词,对分词后的结果进行查询,文档只要包含match查询条件的一部分就会被返回。

match phrase

例如查询quick brown这俩关键词时,保证俩连在一起且保证顺序,即brown a quick和brown quick都不会被搜到。

match phrase prefix

较match phrase而言它增加了,quick brown f时,允许f前缀匹配。

term查keyword类型,其他查text类型。

———————————————————————————————————————————

elasticSearch 设置fields字段的keyword属性, 可精确匹配text类型

https://blog.csdn.net/u012976879/article/details/86598032

{

"svc_search_spider_item" : {

"mappings" : {

"properties" : {

"created_at" : {

"type" : "long"

},

"item_id" : {

"type" : "keyword"

},

"last_crawled_at" : {

"type" : "long"

},

"status" : {

"type" : "long"

},

"task_id" : {

"type" : "keyword"

},

"title" : {

"type" : "text",

"fields" : {

"standard" : {

"type" : "text",

"analyzer" : "standard"

},

"key":{

"type":"keyword"

}

},

"analyzer" : "my_ik_max_word",

"search_analyzer" : "my_ik_smart"

}

}

}

}

}

boolMap["must"] = M{

"multi_match": M{

"query": strings.TrimSpace(req.GetKeyword()),

"type": "phrase_prefix",

"fields": []string{"name.standard"},

},

}

boolMap["must"] = M{

"multi_match": M{

"query": strings.TrimSpace(req.GetKeyword()),

"type": "phrase_prefix",

"fields": []string{"name.key"},

},

}

刷新数据

POST /svc_search_spider_item/_update_by_query

{

"query": {

"match_all": {}

}

}

修改es的index的mapping 增加字段

dev环境:ssh bolome@47.98.144.219

stag环境:kubectl exec -it centos7-59b89689cd-nv88k -- /bin/bash

curl --location --request PUT 'http://172.16.1.23:9200/svc_search_topic/_mapping' \

--header 'Content-Type: application/json' \

--data-raw '{

"properties": {

"catalogue": {

"type": "text",

"fields": {

"standard": {

"type": "text",

"analyzer": "standard"

}

},

"analyzer": "my_ik_max_word",

"search_analyzer": "my_ik_smart"

},

"contentNum": {

"type": "long"

},

"contentViews": {

"type": "long"

},

"created_at": {

"type": "long"

},

"desc": {

"type": "text",

"fields": {

"standard": {

"type": "text",

"analyzer": "standard"

}

},

"analyzer": "my_ik_max_word",

"search_analyzer": "my_ik_smart"

},

"end_at": {

"type": "long"

},

"id": {

"type": "keyword"

},

"mpNum": {

"type": "long"

},

"sort": {

"type": "long"

},

"start_at": {

"type": "long"

},

"title": {

"type": "text",

"fields": {

"standard": {

"type": "text",

"analyzer": "standard"

}

},

"analyzer": "my_ik_max_word",

"search_analyzer": "my_ik_smart"

},

"status": {

"type": "long"

}

}

}'

也可以只写新增的字段:

PUT cimissgcdb/_mapping/agmedays

{

"properties": {

"TimeFormat": {

"type": "date",

"format": "yyyy-MM-dd HH:mm:ss"

}

}

}

———————————————————————————————————————————

空间检索、函数查询等

 查询距离和价格合适,且符合品类限制的小区,并排序

{
	"query": {
	  "function_score": {
		"functions": [
		  {
			"linear": {
			  "sort_1_flt": {
				"origin": 2000,
				"offset": 2000,
				"scale": 5000000,
				"decay": 0.01
			  }
			}
		  },
		  {
			"linear": {
			  "loc": {
				"origin": {
				  "lon": %v,
				  "lat": %v
				},
				"offset": "1km",
				"scale": "100km",
				"decay": 0.01
			  }
			}
		  }
		],
		"query": {
		  "bool": {
			"must": [
			  {
				"term": {
				  "city_id": "%v"
				}
			  },
			  {
				"term": {
				  "biz_sub_type": "%v"
				}
			  }
			],
			"must_not": [
			  {
				"term": {
				  "poi_bids": "%v"
				}
			  },
			  {
				"term": {
				  "sort_1_flt": 0
				}
			  }
			]
		  }
		}
	  }
	},
	"sort": [
	  {
		"weight": {
		  "order": "desc"
		}
	  },
	  {
		"_score": {
		  "order": "desc"
		}
	  }
	],
	"from": %v,
	"size": %v
  }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值