一、ElasticSearch 简介

ElasticSearch 简称 ES ,是于Apache Lucene构建的开源搜索引擎,ES主要以轻量级JSON作为数据存储格式,同时也支持地理位置查询 。官方文档

适用场景有:

  • 海量数据的关键字检索和存储,例如电商网站的关键词搜索商品信息
  • 收集、存储和分析日志,指标和安全事件数据,比如ELK(ElasticSearch, Logstash, Kibana)
  • 做为地理信息系统(GIS) 管理,集成和分析空间信息

二、 文档和索引

Elasticsearch是一个分布式文档存储。存储已序列化为JSON文档的复杂数据结构。当集群中有多个Elasticsearch节点时,存储的文档将分布在集群中,并且可以从任何节点立即访问存储文档时,将在1秒内几乎实时地对其进行索引和完全搜索。Elasticsearch使用称为倒排索引的数据结构,该结构支持非常快速的全文本搜索。

1、索引(index)

索引类似于关系型数据库中Database 的概念, 比如电商系统中,按微服务的方式划分,可以分为商品索引、订单索引、会员索引等等,类似于关系数据库中的 商品库, 订单库和会员库,但索引命名必须全部用小写字母。
索引是映射类型的容器, elasticsearch中的索引是一个非常大的文档集合。索|存储了映射类型的字段和其他设置。然后它们被存储到了各个分片上了。

2、类型(type)

在一个索引中可以有多个类型, 类似关系数据库中的表, 比如订单索引中可以有订单主类型、订单明细类型、订单评价类型等。

在5.x版本以前可以在一个索引中定义多个类型,6.x之后版本也可以使用,但是不推荐,在7~8.x版本中彻底移除一个索引中创建多个类型

3、映射(mapping)

它类似于传统关系型数据中table的schema,用于定义一个索引(index)中的类型(type)的数据的结构。 在ES中,我们可以手动创建type(相当于table)和mapping(相关与schema),也可以采用默认创建方式。在默认配置下,ES可以根据插入的数据自动地创建type及其mapping。 mapping中主要包括字段名、字段数据类型和字段索引类型

4、文档

类似关系表中的一条数据,在这里是指type 中的一条记录或一个json 传,文档采用的是json 方式存储,类似mongoDB 数据库。

三、ES 基本操作

IK提供了两个分词算法: ik_ smart和ik_ max_ word ,其中ik_ smart为最少切分, ik_ max_ _word为最细粒度划分!

GET _analyze
{
  "analyzer": "ik_smart",
  "text": "我是社会主义接班人"
}
GET _analyze
{
  "analyzer": "ik_max_word",
  "text": "我是社会主义接班人"
}

以下操作,可以推荐在kibana 上进行。

1、索引(index)操作
# 创建索引
PUT /world/

# 查看索引
GET /_cat/indices?v

# 删除指定索引
DELETE /world

一般添加文档(document)数据时,会自动创建索引,在api 引用时,会根据model 类型自动创建类型(type)

es数据存储分配不均衡 es数据存储位置_es6.0

2、类型(type)操作
# 在 world索引下创建 person 类型
PUT /world
{
  "mappings": {
    "person":{
      "properties":{
        "id": {"type": "integer"},
        "name" : {"type": "text"},
        "age" : {"type":"integer"},
        "birth" : {"type":"date"}
      }
    }
  }
}

# 查看类型
GET /world/_mapping/person
3、文档(document) 基本操作
# 添加文档 /索引/类型/id 多次执行,新的数据覆盖老的
PUT /world/person/1
{
  "id":1,
  "name":"panlei2",
  "age":31,
  "birth":"1991-09-02"
}

# 查询文档
GET /world/person/1

# 删除文档
DELETE /world/person/1

# 更新文档
# 1、更新原有数据
POST /world/person/1/_update
{
  "doc":{
    "age":29
  }
}

# 添加新数据
POST /world/person/1/_update
{
  "doc": {
    "name":"lei",
    "nickname":"leilei",
    "nickLike":"ll"
  }
}

# 在原有数据上更新
POST /world/person/1/_update
{
  "script": "ctx._source.age+=5"
}

es数据存储分配不均衡 es数据存储位置_es6.8_02

批量操作:

# 1、 批量索引两个文档
PUT /world/person/_bulk
{"index":{"_id":2}}
  	{"name":"yy","age":25,"birth":"2020-09-07"}
{"index":{"_id":3}}
  	{"name":"hc","age":2,"birth":"2020-09-01"}
  
# 2、更新文档同时删除文档
POST /world/person/_bulk
{"update":{"_id":"1"}}
  	{"doc":{"name":"PL"}}
{"delete":{"_id":2}}
{"index":{"_id":3}}
  	{"age":12}

四、高级检索 Start Searching

ES官方提供了两中检索方式:一种是通过 URL 参数进行搜索,另一种是通过 DSL(Domain Specified Language) 进行搜索。官方更推荐使用第二种方式,第二种方式是基于传递JSON作为请求体(request body)格式与ES进行交互,这种方式更强大,更简洁。

1、URL 参数查询: GET /world/person/_search?参数

# q:查询 sort:排序  size:每页返回条数  from:第几页开始(0) _source:展示哪几个字段
GET /ems/emp/_search?q=*&sort=age:desc&size=10&from=0&_source=name,age

2、DSL查询: GET /index/type/_search {请求体}

# 1、查询所有
GET /world/person/_search
{
  "query": {
    "match_all": {}
  }
}

# 2、查询所有并排序
GET /world/person/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ]
}

#3、分页查询
GET /world/person/_search
{
  "query": {
    "match_all": {}
  },
  "size": 10,
  "from": 0,
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ]
}

# 4、指定查询结果返回指定字段
GET /world/person/_search
{
  "query": {
    "match_all": {}
  },\
  "_source": ["name","age"]
}

# 5、 term查询,基于关键词查询
GET /world/person/_search
{
  "query": {
    "term": {
      "content": {
        "value": "spring"
      }
    }
  }
}

# 6、分析分词
GET /_analyze
{
  "text": "hello world"
}

1、text 类型是分词的,ES 默认使用标准分词器,标准分词是按字分词,英语是按单词分词
2、在ES 中,只有text 会分词,其他类型不分词

ES 索引库原理:

es数据存储分配不均衡 es数据存储位置_es6.0_03

# 范围查询
GET /ems/emp/_search
{
  "query": {
    "range": {
      "age": {
        "gte": 0,
        "lte": 20
      }
    }
  }
}

# 关键词前缀查询
GET /ems/emp/_search
{
  "query": {
    "prefix": {
      "name": {
        "value": "小"
      }
    }
  }
}

# 通配符查询 *通配所有 ?匹配一个
GET /ems/emp/_search
{
  "query": {
    "wildcard": {
      "address": {
        "value": "北*"
      }
    }
  }
}

# 多id 查询
GET /ems/emp/_search
{
  "query": {
    "ids": {
      "values": ["gQAvaXQBqXUotQFEybN-","jwAvaXQBqXUotQFEzbPe"]
    }
  }
}

# fuzzy 模糊查询 最大模糊错误 必须在0-2之间
GET /ems/emp/_search
{
  "query": {
    "fuzzy": {
      "content": "Sprong"
    }
  }
}

# 布尔查询 must shoud must_not
GET /ems/emp/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "age": {
              "value": "23"
            }
          }
        },
        {
          "term": {
            "address": {
              "value": "北京"
            }
          }
        }
      ]
    }
  }
}

# 高亮查询 对查询结果做渲染
GET /ems/emp/_search
{
  "query": {
    "term": {
      "content": {
        "value": "redis"
      }
    }
  },
  "highlight": {
    "fields": {
      "*":{}
    },
    "pre_tags": ["<span style='color:red'>"],
    "post_tags": ["</span>"]
  }
}

五、安装IK 分词器

Git 地址

在线安装:

./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.3.0/elasticsearch-analysis-ik-6.3.0.zip

离线安装:
1、在git 仓库找到版本对应的tag,下载到服务器
2、解压到 plugin/ik 目录下,直接启动es 就可以(es中如果有数据,就先删除数据)

测试IK 分词是否安装成功

GET /_analyze
{
  "text": "中华人民共和国国歌",
  "analyzer": "ik_max_word"
}

ik_max_word: 会将文本做最细粒度的拆分`,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”

ik_smart: 会做最粗粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”。

当使用Ik 分词器时,需要重新指定分词器

PUT /world
{
  "mappings": {
    "person":{
      "properties":{
        "id": {"type": "integer"},
        "content" : {"type": "text","analyzer": "ik_max_word"},
        "age" : {"type":"integer"},
        "birth" : {"type":"date"}
      }
    }
  }
}

这时候可以用关键词查询一下:

GET /world/person/_search
{
  "query": {
    "term": {
      "content": {
        "value": "框架"
      }
    }
  }
}

如果想修改分词器的词典,修改文件

elasticsearch-6.8.12/plugins/ik/config/IKAnalyzer.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>

<properties>
	<comment>IK Analyzer 扩展配置</comment>
	<!--用户可以在这里配置自己的扩展字典 -->
	<entry key="ext_dict">custom/mydict.dic;custom/single_word_low_freq.dic</entry>
	 <!--用户可以在这里配置自己的扩展停止词字典-->
	<entry key="ext_stopwords">custom/ext_stopword.dic</entry>
 	<!--用户可以在这里配置远程扩展字典 -->
	<entry key="remote_ext_dict">location</entry>
 	<!--用户可以在这里配置远程扩展停止词字典-->
	<entry key="remote_ext_stopwords">http://xxx.com/xxx.dic</entry>
</properties>

六、过滤查询

语法:

GET /ems/emp/_search
{
  "query": {
    "bool": {
      "must": [
        {"match_all": {}}
      ],
      "filter": {
        "range": {
          "age": {
            "gte": 10
          }
        }
      }
    }
  }
}

1、在执行filter和query时,先执行filter在执行query

2、Elasticsearch会自动缓存经常使用的过滤器,以加快性能。

常见的过滤器类型

GET /ems/emp/_search   # 使用term过滤
{
  "query": {
    "bool": {
      "must": [
        {"term": {
          "name": {
            "value": "小黑"
          }
        }}
      ],
      "filter": {
        "term": {
          "content":"框架"
        }
      }
    }
  }
}
GET /dangdang/book/_search  #使用terms过滤
{
  "query": {
    "bool": {
      "must": [
        {"term": {
          "name": {
            "value": "中国"
          }
        }}
      ],
      "filter": {
        "terms": {
          "content":[
              "科技",
              "声音"
            ]
        }
      }
    }
  }
}

ranage filter:

GET /ems/emp/_search
{
  "query": {
    "bool": {
      "must": [
        {"term": {
          "name": {
            "value": "中国"
          }
        }}
      ],
      "filter": {
        "range": {
          "age": {
            "gte": 7,
            "lte": 20
          }
        }
      }
    }
  }
}

exists filter

过滤存在指定字段,获取字段不为空的索引记录使用

GET /ems/emp/_search
{
  "query": {
    "bool": {
      "must": [
        {"term": {
          "name": {
            "value": "中国"
          }
        }}
      ],
      "filter": {
        "exists": {
          "field":"aaa"
        }
      }
    }
  }
}

ids filter

过滤含有指定字段的索引记录

GET /ems/emp/_search
{
  "query": {
    "bool": {
      "must": [
        {"term": {
          "name": {
            "value": "中国"
          }
        }}
      ],
      "filter": {
        "ids": {
          "values": ["1","2","3"]
        }
      }
    }
  }
}