Elasticsearch基础知识及实践应用

目录

    • 一、Elasticsearch 核心概念
    • 二、Elasticsearch安装
    • 三、Elasticsearch基础命令
          • 1. 快速获取集群状态
          • 2.创建索引
          • 3.查看索引
          • 4.查看全部索引 ?v:显示每一列的含义
          • 5.删除索引
          • 6.创建索引的同时创建mappings
          • 7.查看分词效果
          • 8.更改mapping映射 添加映射
          • 9.为已存在的索引创建mappings
          • 10.添加文档
          • 11.删除文档
          • 12.局部修改
          • 13.全量替换
          • 14.查询文档
          • 15.文档乐观锁控制 if_seq_no与if_primary_term
          • 16.es内置分词器
          • 17.安装ik中文分词器
          • 18.自定义中文词库
    • 四、DSL搜索
          • 1.前置准备
          • 2.请求参数的查询(QueryString)
          • 3.DSL基本语法
          • 4.查询所有与分页
          • 5.term精确搜索与match分词搜索
          • 6.match_phrase 短语匹配
          • 7. match(operator)/ids
          • 8. multi_match/boost
          • 9. 布尔查询
          • 10.过滤器
          • 11.排序
          • 12.高亮显示
          • 13. prefix \ fuzzy \ wildcard
          • 14.深度分页
          • 15.scroll 滚动搜索
          • 16.批量操作 bulk

一、Elasticsearch 核心概念

当前Elasticsearch版本号:7.3.2

Elasticsearch 关系型数据库
ES 数据库
索引index
文档 document 行(记录)
字段 fields

分片(shard)

shard = primary shard(主分片)

把索引库拆分为多份,分别放在不同的节点上,比如有3个节点,3个节点的所有数据内容加在一起是一个完整的索引库。分别保存到三个节点上水平扩展,提高吞吐量。

备份(replica)

replica = replica shard(备份节点)

每个shard的备份。

二、Elasticsearch安装

将下载好的Elasticsearch上传至Linux服务器

  1. 解压
  2. 将解压后的目录移至/usr/local下:mv elasticsearch-7.3.2 /opt
  3. 在elasticsearch-7.3.2目录下,创建data文件夹作为索引目录:mkdir data

目录介绍

  • bin:可执行文件在里面,运行es的命令就在这个里面,包含了一些脚本文件等
  • config:配置文件目录
  • JDK:java环境
  • lib:依赖的jar,类库
  • logs:日志文件
  • modules:es相关的模块
  • plugins:可以自己开发的插件
  • data:索引目录

修改核心配置文件 elasticearch.yml,config目录下

  • 修改集群名称,默认是elasticsearch,目前是单机,但也有默认的
  • 为当前的es节点取个名称,名称随意,如果在集群环境中,都要有相应的名字
# 集群名
cluster.name: my-application
# 当前节点
node.name: node-1
# 索引目录
path.data: /opt/elasticsearch-7.3.2/data
# 日志
path.logs: /opt/elasticsearch-7.3.2/logs
# 允许所有IP
network.host: 0.0.0.0
# 符合master节点条件的节点,多个逗号分隔
cluster.initial_master_nodes: ["node-1"]

三、Elasticsearch基础命令

1. 快速获取集群状态
GET /_cluster/health
2.创建索引
PUT /index_one

{
    "settings":{
        "index":{
            # 分片数
            "number_of_shards":"2",
            # 副本数
            "number_of_replicas":"0"
        }
    }
}
3.查看索引
GET /index_one
4.查看全部索引 ?v:显示每一列的含义
GET /_cat/indices?v
5.删除索引
DELETE /index_one
6.创建索引的同时创建mappings
PUT /index_one
 
{
    "mappings":{
        "properties":{
            "username":{
                "type":"text",  # 字符串类型
                "index":true    # 为该属性创建索引
            },
            "sign":{
               "type":"text",
               "index":true
            },
            "sex":{
                "type":"keyword", # 不分词
                "index":false  # 不创建索引
            }
        }
    }
}
7.查看分词效果
GET /index_one/_analyze
 
{
    "field":"username",
    "text":"my name is DingWenhao"
}
8.更改mapping映射 添加映射
PUT /index_one/_mapping
 
{
    "properties":{
        "name":{
            "type":"long"
        }
    }
}

9.为已存在的索引创建mappings
POST /index_one/_mapping
 
{
    "properties":{
            "username":{
                "type":"text",
                "index":true
            },
            "sign":{
               "type":"text",
               "index":true
            },
            "sex":{
                "type":"keyword",
                "index":false
            }
        }
}

10.添加文档
# {索引名}/_doc/{索引ID}
POST /index_one/_doc/1 

{
    "id":"1",
    "username":"ding wen hao",
    "sign":"Java小白",
    "sex":"男"
}

11.删除文档
# 文档删除不是立即删除,文档还是保存在磁盘上,索引增长越来越多,才会把那些曾经标识过删除的,进行清理
DELETE /index_one/_doc/1

12.局部修改
# 每次修改后,version会更改
POST /index_one/_doc/1/_update

{ 
    "doc": { 
        "username": "ding ding ding" 
    } 
}

13.全量替换
# 每次修改后,version会更改
PUT /index_one/_doc/1

{
    "id":"1",
    "username":"ding wen hao ya ya",
    "sign":"Java小白",
    "sex":"男"
}

14.查询文档
# {索引}/_doc/{id}
GET /index_one/_doc/1

返回数据说明:

_index:文档数据所属那个索引,理解为数据库的某张表即可。

_type:文档数据属于哪个类型,新版本使用 _doc 。

_id:文档数据的唯一标识,类似数据库中某张表的主键。可以自动生成或者手动指定。

_score:查询相关度,是否契合用户匹配,分数越高用户的搜索体验越高。

_version:版本号。

_source:文档数据,json格式。

# 其他方式
GET /index_one/_doc/_search
# 定制结果集
GET /index_one/_doc/1?_source=id,username
GET /index_one/_doc/_search?_source=id,username
# 判断文档是否存在
HEAD /index_one/_doc/1

15.文档乐观锁控制 if_seq_no与if_primary_term

_seq_no: 文档版本号,作用同version

_primary_term: 文档所在的位置

# 操作1 
POST /index_one/_doc/{_id}/_update?if_seq_no={数值}&if_primary_term={数值} 
{ 
    "doc": { 
        "username": "ding ding ding hei" 
    } 
}

# 操作2 
POST /index_one/_doc/{_id}/_update?if_seq_no={数值}&if_primary_term={数值} 
{ 
    "doc": { 
        "username": "ding ding ding hei hei ya" 
    } 
}

两个操作并发执行,仅有一个可执行成功

16.es内置分词器
  • standard:默认分词,单词会被拆分,大小会转换为小写。
  • simple:按照非字母分词。大写转为小写。
  • whitespace:按照空格分词。忽略大小写。
  • stop:去除无意义单词,比如 the / a / an / is …
  • keyword:不做分词。把整个文本作为一个单独的关键词。
17.安装ik中文分词器
地址: https://github.com/medcl/elasticsearch-analysis-ik/releases 

选择与Elasticsearch对应版本的进行下载即可

unzip elasticsearch-analysis-ik-7.3.2.zip -d /ik

测试中文分词
POST /_analyze
{ 
    "analyzer": "ik_max_word", 
    "text": "你好呀,今天也要努力学习哟" 
}

18.自定义中文词库
1. 在{es}/plugins/ik/config下,创建custom.dic
	vi custom.dic
2. 添加内容
	自定义即可,每个词汇需换行
3. 配置自定义扩展词典
	vi IKAnalyzer.cfg.xml
	配置:
		custom.dic
4. 重启即可

四、DSL搜索

1.前置准备

创建索引 index_two

PUT /index_two
{
    "settings":{
        "index":{
            "number_of_shards":"2",
            "number_of_replicas":"0"
        }
    }
}

创建mapping

POST /index_two/_mapping
{
    "properties": {
        "id": {
            "type": "long"
        },
        "age": {
            "type": "integer"
        },
        "username": {
            "type": "keyword"
        },
        "nickname": {
            "type": "text",
            "analyzer": "ik_max_word"
        },
        "money": {
            "type": "float"
        },
        "desc": {
            "type": "text",
            "analyzer": "ik_max_word"
        },
        "sex": {
            "type": "byte"
        },
        "birthday": {
            "type": "date"
        },
        "face": {
            "type": "text",
            "index": false
        }
    }
}

添加五条测试数据

POST /index_two/_doc/1
{
    "id":1,
    "age":18,
    "username":"丁文浩",
    "nickname":"这个橘子超甜",
    "money":"99.99",
    "desc":"一个热爱学习的搬砖少年!",
    "sex":"0",
    "birthday":"1996-07-22",
    "face":"XXX"
}

POST /index_two/_doc/2
{
    "id":2,
    "age":22,
    "username":"张三",
    "nickname":"舍我其谁",
    "money":"25.9",
    "desc":"帮我带一瓶冰阔落",
    "sex":"0",
    "birthday":"1992-01-22",
    "face":"(*≧m≦*)"
}

POST /index_two/_doc/3
{
    "id":3,
    "age":44,
    "username":"项羽",
    "nickname":"至今思项羽,不肯过江东",
    "money":"199.9",
    "desc":"生当作人杰,死亦为鬼雄",
    "sex":"0",
    "birthday":"1969-03-12",
    "face":"ha ha ha ~"
}

POST /index_two/_doc/4
{
    "id":4,
    "age":37,
    "username":"吕布",
    "nickname":"我的貂蝉在哪里!",
    "money":"199.9",
    "desc":"此时,貂蝉还在骑马赶来的路上",
    "sex":"0",
    "birthday":"1962-03-12",
    "face":"lue lue lue~"
}

POST /index_two/_doc/5
{
    "id":5,
    "age":45,
    "username":"段天涯",
    "nickname":"我全都要",
    "money":"36.6",
    "desc":"东瀛剑法",
    "sex":"0",
    "birthday":"1964-03-12",
    "face":"xiu xiu xiu"
}

2.请求参数的查询(QueryString)
# keyword不会被倒排索引,不会被分词
GET /index_two/_doc/_search?q=desc:剑法
GET /index_two/_doc/_search?q=desc:剑法&q=nickname:橘子

3.DSL基本语法

QueryString用的很少,一旦参数复杂就难以构建,所以大多查询都会使用dsl来进行查询更好。

  • Domain Specific Language
  • 特定领域语言
  • 基于JSON格式的数据查询
  • 查询更灵活,有利于复杂查询
# 查询
GET /index_two/_doc/_search
{
    "query":{
        "match": {
            "nickname": "好甜呀"
        }
    }
}

# 判断某个字段是否存在
GET /index_two/_doc/_search
{
    "query":{
        "exists": {
            "field": "nickname"
        }
    }
}

4.查询所有与分页
# 在索引中查询所有的文档
GET /index_two/_doc/_search

# 或 _source展示部分字段
POST /index_two/_doc/_search 
{
    "query": {
        "match_all": {}
    },
    "_source": [
        "id",
        "username",
        "desc"
    ]
}

# 或
POST /index_two/_doc/_search 
{
    "query": {
        "match": {
            "desc":"热爱学习的剑法"
        }
    }
}

# 带分页的查询
POST /index_two/_doc/_search 
{
    "query": {
        "match_all": {}
    },
    "_source": [
        "id",
        "username",
        "desc"
    ],
    "from": 0,
    "size": 5
}

5.term精确搜索与match分词搜索
# term 作为一整个关键词去搜索,match则是进行分词后搜索
POST /index_two/_doc/_search 
{
    "query": {
        "term": {
            "desc":"少年"
        }
    }
}

# 或 多词汇搜索
{
    "query": {
        "terms": {
            "desc":["少年","剑法","帮我"]
        }
    }
}

6.match_phrase 短语匹配

match:分词后只要有匹配就返回

match_phrase:分词结果必须在text字段分词中都包含,而且顺序必须相同,而且必须都是连续的。

slop:允许词语间跳过的数量

POST /index_two/_doc/_search 
{
    "query": {
        "match_phrase": {
            "desc": {
                "query": "热爱 学习 少年",
                "slop": 4
            }
        }
    }
}

7. match(operator)/ids

operator :

​ or:搜索内容分词后,只要存在一个词语匹配就展示结果

​ and:搜索内容分词后,都要满足词语匹配

POST /index_two/_doc/_search 
{
    "query": {
        "match": {
            "desc": {
                "query": "喜欢冰阔乐的少年爱学习",
                "operator": "or"
            }
        }
    }
}
相当于:
	select * from index_two where desc='冰阔乐' or desc='学习'

POST /index_two/_doc/_search 
{
    "query": {
        "match": {
            "desc": {
                "query": "热爱学习的少年",
                "operator": "and"
            }
        }
    }
}
相当于:
	select * from index_two where desc='热爱' and desc='学习' and desc='的' and desc='少年'

minimum_should_match:

​ 最低匹配精度,至少有[分词后的词语个数]x百分百,得出一个数据值取整。举个例子:当前属性设置为 70 ,若一个用户查询有10个词语,那么匹配度按照 10x70%=7,则desc中至少需要有7个词语匹配,就展示;若分词后有8个,则 8x70%=5.6,则desc中至少需要有5个词语匹配,minimum_should_match也能设置具体的数字,表示个数

POST /index_two/_doc/_search 
{
    "query": {
        "match": {
            "desc": {
                "query": "热爱学习的少年",
                "minimum_should_match": "60%"
            }
        }
    }
}

根据id批量查询

POST /index_two/_doc/_search 
{
    "query":{
        "ids":{
            "type":"_doc",
            "values" : ["1", "4"]
        }
    }
}

8. multi_match/boost

multi_match:
满足使用match在多个字段中进行查询的需求

POST /index_two/_doc/_search
{
    "query": {
        "multi_match": {
            "query": "段天涯",
            "fields": [
                "username",
                "desc"
            ]
        }
    }
}

boost:
权重,为某个字段设置权重,权重越高,文档相关性得分就越高。通畅来说搜索商品名称要比商品简介的权重更高。

​ username^10 代表搜索提升10倍相关性,也就是说用户搜索的时候其实以这个username为主,desc为辅,username的匹配相关度当然要提高权重比例了。

POST /index_two/_doc/_search
{
    "query": {
        "multi_match": {
            "query": "段天涯",
            "fields": [
                "username^10",
                "desc"
            ]
        }
    }
}

9. 布尔查询

可以组合多重查询

  • must:查询必须匹配搜索条件,譬如 and
  • should:查询匹配满足1个以上条件,譬如 or
  • must_not:不匹配搜索条件,一个都不要满足
# 多个字段汇总有[段天涯]并且sex为[0],birthday[1964-03-12]
POST /index_two/_doc/_search
{
    "query": {
        "bool": {
            "must": [
                {
                    "multi_match": {
                        "query": "段天涯",
                        "fields": [
                            "desc",
                            "username"
                        ]
                    }
                },
                {
                    "term": {
                        "sex": 0
                    }
                },
                {
                    "term": {
                        "birthday": "1964-03-12"
                    }
                }
            ]
        }
    }
}

10.过滤器

​ 对搜索出来的结果进行数据过滤。不会到es库里去搜,不会去计算文档的相关度分数,所以过滤的性能会比较高,过滤器可以和全文搜索结合在一起使用。
​ post_filter元素是一个顶层元素,只会对搜索结果进行过滤。不会计算数据的匹配度相关性分数,不会根据分数去排序,query则相反,会计算分数,也会按照分排序

使用场景:
query:

​ 根据用户搜索条件检索匹配记录
​ post_filter:

​ 用于查询后,对结果数据的筛选
​ gte:大于等于
​ lte:小于等于
​ gt:大于
​ lt:小于
(除此以外还能做其他的match等操作也行)

# 筛选结果中账户金额大于50元,小于200元的用户
POST /index_two/_doc/_search
{
    "query": {
        "match": {
            "desc": "爱学习的少年"
        }
    },
    "post_filter": {
        "range": {
            "money": {
                "gt": 50,
                "lt": 200
            }
        }
    }
}

11.排序

es的排序同sql,可以desc也可以asc。也支持组合排序。

POST /index_two/_doc/_search
{
    "query": {
        "match": {
            "desc": "爱学习的少年"
        }
    },
    "post_filter": {
        "range": {
            "money": {
                "gt": 50,
                "lte": 200
            }
        }
    },
    "sort": [
        {
            "age": "desc"
        },
        {
            "money": "desc"
        }
    ]
}

对文本排序
由于文本会被分词,所以往往要去做排序会报错,通常我们可以为这个字段增加额外的一个附属属性,类型为keyword,用于做排序。

# 创建新的索引
POST /index_three/_mapping
{
    "properties": {
        "id": {
            "type": "long"
        },
        "nickname": {
            "type": "text",
            "analyzer": "ik_max_word",
            "fields": {
                "keyword": {
                    "type": "keyword"
                }
            }
        }
    }
}

12.高亮显示
POST /index_two/_doc/_search
{
    "query": {
        "match": {
            "desc": "爱学习的少年"
        }
    },
    "highlight": {
        "pre_tags": [
            ""
        ],
        "post_tags": [
            ""
        ],
        "fields": {
            "desc": {}
        }
    }
}

13. prefix \ fuzzy \ wildcard

prefix :

​ 根据前缀去查询

POST /index_two/_doc/_search
{
    "query": {
        "prefix": {
            "username": "ding"
        }
    }
}

fuzzy :
模糊搜索,并不是指的sql的模糊搜索,而是用户在进行搜索的时候的打字错误现象,搜索引擎会自动纠正,然后尝试匹配索引库中的数据。

POST /index_two/_doc/_search
{
    "query": {
        "fuzzy": {
            "username": "丁文号"
        }
    }
}

# 多字段搜索
{
    "query": {
        "multi_match": {
            "fields": [
                "username",
                "desc"
            ],
            "query": "丁文号",
            "fuzziness": "AUTO"
        }
    }
}

wildcard:

​ 占位符查询,性能较差

POST /index_two/_doc/_search
{
    "query": {
        "regexp": {
            "username": "jav[a-z]*"
        }
    }
}

14.深度分页
# 查询设置
GET /index_two/_settings

PUT /index_two/_settings
{
    "index.max_result_window": "20000"
}

15.scroll 滚动搜索

​ 一次性查询1万+数据,往往会造成性能影响,因为数据量太多了。这个时候可以使用滚动搜索,也就是 scroll 滚动搜索可以先查询出一些数据,然后再紧接着依次往下查询。在第一次查询的时候会有一个滚动id,相当于一个 锚标记 ,随后再次滚动搜索会需要上一次搜索,根据这个进行下一次的搜索请求。每次搜索都是基于一个历史的数据快照,查询数据的期间,如果有数据变更,那么和搜索是没有关系的.
​ scroll=1m,相当于是一个session会话时间,搜索保持的上下文时间为1分钟。

POST /index_two/_search?scroll=3m

{
    "query": {
        "match_all": {}
    },
    "sort": [
        "_doc"
    ],
    "size": 5
}

POST /_search/scroll
{
    "scroll": "3m",
    "scroll_id": "上一个请求返回的scroll_id"
}

16.批量操作 bulk

​ bulk操作和以往的普通请求格式有区别。不要格式化json,不然就不在同一行了,这个需要注意。

{ action: { metadata }}\n 

{ request body }\n 

{ action: { metadata }}\n 

{ request body }\n 

... 

说明:
	{ action: { metadata }} 
    	代表批量操作的类型,可以是新增、删除或修改 
	\n 
    	是每行结尾必须填写的一个规范,每一行包括最后一行都要写,用于es的解析 
    { request body } 
    	是请求body,增加和修改操作需要,删除操作则不需要 
    
    批量操作的类型 :
    	action 必须是以下选项之一: 

			create:如果文档不存在,那么就创建它。存在会报错。发生异常报错不会影响其他操作。 

			index:创建一个新文档或者替换一个现有的文档。 

			update:部分更新一个文档。 

			delete:删除一个文档。 

	metadata中需要指定要操作的文档的 _index 、 _type 和 _id , _index 、 _type 也可以在url中指定 

注:最后一行也需要换行

示例一:create新增文档数据,在metadata中指定index以及type

POST /_bulk
{"create": {"_index": "index_two", "_type": "_doc", "_id": "1001"}} 
{"id": "1001", "username": "username1001"} 
{"create": {"_index": "index_two", "_type": "_doc", "_id": "1002"}} 
{"id": "1002", "username": "username1002"} 
{"create": {"_index": "index_two", "_type": "_doc", "_id": "1003"}} 
{"id": "1003", "username": "username1003"}


示例二:create创建已有id文档,在url中指定index和type

POST /index_two/_doc/_bulk
{"create": {"_id": "1003"}}
{"id": "1003", "username": "username1003"}
{"create": {"_id": "1004"}}
{"id": "1004", "username": "username1004"}
{"create": {"_id": "1005"}}
{"id": "1005", "username": "username1005"}


示例三:index创建,已有文档id会被覆盖,不存在的id则新增

POST /index_two/_doc/_bulk
{"index": {"_id": "1005"}}
{"id": "1005", "username": "index-username1005"}
{"index": {"_id": "1006"}}
{"id": "1006", "username": "username1006"}
{"index": {"_id": "1007"}}
{"id": "1007", "username": "username1007"}



你可能感兴趣的:(Java)