第二章:Kibnan中操作ElasticSearch

392 阅读6分钟

ES的基本操作

我正在参加「掘金·启航计划」

本次操作将在 Kiana中进行

当然你也可以在 PostMan 或者浏览器搜索框 等等能发送请求的地方进行

1. 测试分词器

1.1 测试 IK 分词器

使用 Kianan的控制台进行测试

Kibnan控制台测测试 最少切分

GET _analyze
{
  "analyzer": "ik_smart",
  "text": "Redis中国网站" #要切分的文本
}

Kibnan控制台 最细粒度切分

GET _analyze
{
  "analyzer": "ik_max_word", # 最细粒度切分  穷尽词库的可能!字典!
  "text": "Redis中国网站" # 要切分的文本
}

IK 添加自定义词语

添加自定义词语之前

设置自定义词语之后

通过以上测试结果可以看到 不管是哪种切分方式 都会根据你的词库来进行切分

  • ik_smart 最粗粒度切分
  • ik_max_word 最细粒度切分

1.2 测试 pinyin 分词器

  • 测试步骤与 ik 一致
GET _analyze
{
  "analyzer": "pinyin",
  "text": ["中国"]
}

返回结果

可以看到 拆分结果为 每个汉字的全拼拼音 和 每个汉字的首字母 所以结果就是

  • zhong : 中
  • zg 中国
  • guo 国
{
  "tokens" : [
    {
      "token" : "zhong",
      "start_offset" : 0,
      "end_offset" : 0,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "zg",
      "start_offset" : 0,
      "end_offset" : 0,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "guo",
      "start_offset" : 0,
      "end_offset" : 0,
      "type" : "word",
      "position" : 1
    }
  ]
}

2. 关于索引的基本操作

1.1创建索引

  • 创建索引
PUT /索引名称
  • 创建索引同时设置索引的参数
    • 分片数
    • 副本数 等配置
PUT /sc
{
  "settings": {
    "number_of_shards": 5,  
    "number_of_replicas": 1
  }
}

创建索引

该种方式为自动创建索引 而且数据也添加成功了

那么为什么不用给字段指定名称呢?

elasticsearch会自动的将新字段加入映射,但是这 个字段的不确定它是什么类型,elasticsearch就开始猜,如果这个值是18,那么elasticsearch会认为它 是整形。 但是elasticsearch也可能猜不对, 所以最安全的方式就是提前定义好所需要的映射,这点跟关 系型数据库殊途同归了,先定义好字段,然后再使用,别 整什么幺蛾子。

1.2 指定字段的类型创建索引

PUT /shop
{
  "mappings": {
    "goods": {
      "properties": {
        "name": {
          "type": "text"
        },
        "price": {
          "type": "double"
        },
        "sjDate": {
          "type": "date"
        }
      }
    }
  }
}

创建索引并指定字段类型

1.3 获取索引信息

  • 获取单个
GET /yufire  # 使用GET请求 直接请求要查询的索引

获取索引信息

  • 获取所有 方式一
GET _cat/indices?v

获取更多的索引信息

  • 方式二
GET /_all

1.4 添加索引映射信息

  • 一旦映射信息固定 就不可以进行修改了
  • 只能进行添加映射操作
POST /shop/_mapping/goods
{
  "properties": {
    "age": {
      "type": "integer"
    }
  }
}

1.5 删除索引

  • 删除单个索引
DELETE /yufire 
  • 删除全部索引
DELETE _all

1.6 自定义分词器

  • 可以再一个属性映射上同时添加多个分词器

1. 首先创建一个索引

ik_smart_pinyin 为我们自定义分词器的名称

​ ik_smart_pinyin 中包含了 ik 和 pinyin 分词器

PUT /IndexName
{
   "settings": {
        "analysis": {
            "analyzer": {
                "ik_smart_pinyin": {
                    "type": "custom",
                    "tokenizer": "ik_smart",
                    "filter": ["my_pinyin", "word_delimiter"]
                },
                "ik_max_word_pinyin": {
                    "type": "custom",
                    "tokenizer": "ik_max_word",
                    "filter": ["my_pinyin", "word_delimiter"]
                }
            },
            "filter": {
                "my_pinyin": {
                    "type" : "pinyin",
                    "keep_separate_first_letter" : true,
                    "keep_full_pinyin" : true,
                    "keep_original" : true,
                    "limit_first_letter_length" : 16,
                    "lowercase" : true,
                    "remove_duplicated_term" : true 
                }
            }
        }
  }
  
}

2. 重新指定文档类型映射拼音分词类型

  • name 只是作为一个示范 其他的映射自行添加
    • 把name属性的analyzer 和 search_analyzer 设置为 我们自定义的 ik_smart_pinyin 分词器即可
POST /goods/_mapping/
{
  "properties": {
    "name": {
      "type": "text",
      "analyzer":"ik_smart_pinyin",
      "search_analyzer":"ik_smart_pinyin"
    }
  }
}

3. 文档操作 重点

基本操作

2.1 创建文档

创建文档操作等于向MySQL中添加数据

img

PUT /yufire/user/1
{
	"name":"yufire",
	"age":3
}
  • 可以不指定id 会自动生成一个字符串作为id
  • 如果创建索引的时候没有指定类型的话 默认类型为 _doc
  • 第一次创建文档的时候 result状态为 created

2.2 获取数据

img

GET /yufire/_doc/1

2.3 修改数据

2.3.1 PUT方式修改

  • 这种方式就是 使用PUT 请求 直接将源数据给覆盖掉 官方并不推荐这种方法
  • 如果修改的参数和mapping映射不一样的话 数据会出现错乱问题

img

PUT /yufire/_doc/1
{
	"name":"yufire2",
	"age":3,
	"birthday":"2020-04-21"
}

2.3.2 POST方式修改

  • POST _update , 官方推荐使用这种更新方式!

img

POST /yufire/_doc/1/_update
{
  "doc":{
    "name":"yufire3"
  }
}

2.4 简单的搜索

img

现在索引库中有 5 条数据

img

GET /yufire/_doc/_search?q=name:yufire1
# 使用GET请求做一个简单的搜索

2.5 复杂的查询 重点

2.5.1 mathc 查询

  • 相当于 like

match query 知道分词器的存在 他会根据分词器进行拆分

如果查询的数据没有在分词器中配置的话 那么就会进行精确查询

分词器中配置了该词的结果img

分词器中没有配置该词的结果

img

GET /yufire/_doc/_search
{
  "query":{
    "match":{
      "name":"中国中央电视"
    }
  }
}

2.5.2 结果过滤

  • 在 query节点后边加上_source 输入过滤字段 即可

img

GET /yufire/_doc/_search
{
  "query":{
    "match":{
      "name":"yufire1"
    }
  },
  "_source":["name","age"]
}

2.5.3 排序

  • 在 query节点后边添加 sort 节点

img

GET /yufire/_doc/_search
{
  "query":{
    "match":{
      "name":"中央"
    }
  },
  "_source":["age"],
  "sort":{
    "age":{
      "order":"asc"
    }
  }
}
# order 的值 根MySQL中对应   asc为升序  desc为降序

2.5.4 分页查询

  • 分页查询与mysql中类似 只需要两个参数即可
  • from : 对应MySQL中的 limit 第一个参数
  • size : 对应MySQL中的 limit 第二个参数
  • limit from,size

img

GET /yufire/_doc/_search
{
  "query":{
    "match":{
      "name":"中央"
    }
  },
  "_source":["age"],
  "sort":{
    "age":{
      "order":"asc"
    }
  },
  "from":0,
  "size":2
}
# limit from,size

2.5.5 布尔值查询 and

  • 多条件查询

  • must (and),所有的条件都要符合 where name=xxx1 and age= xxx

img

GET /yufire/_doc/_search
{
  "query": {
    "bool": {
      "must": [ # 存放条件的数组
        { # 一个个的条件对象
          "match": {
            "name": "中央电视台"
          }
        },
        { # 一个个的条件对象
          "match": {
            "age": 17
          }
        }
      ]
    }
  }
}

2.5.6 布尔值查询 or

  • should 关键字 就等于mysql中的 or
  • should (or) where name=xxx or age=xxx

img

GET /yufire/_doc/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "name": "中央电视台"
          }
        },
        {
          "match": {
            "age": 17
          }
        }
      ]
    }
  }
}

2.5.7 布尔值查询 not

  • must_not 就相当于mysql中的 not

img

GET /yufire/_doc/_search
{
  "query": {
    "bool": {
      "must_not": [
        {
          "match": {
            "age": 17
          }
        }
      ]
    }
  }
}

2.5.8 过滤器 filter

  • 可以使用 filter进行数据的过滤

  • gt 大于

  • gte 大于等于

  • lt 小于

  • lte 小于等于!

img

GET /yufire/_doc/_search
{
  "query": {
    "bool": {
      "must_not": [
        {
          "match": {
            "age": 17
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "gte": 1,
            "lte": 3
          }
        }
      }
    }
  }
}

2.5.9 匹配数组

  • 如果文档中的数据有数组的话 可以直接用match关键字进行匹配

img

GET /yufire/_doc/_search
{
  "query":{
    "match":{
      "tags":"唱  rap"
    }
  }
}
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 0,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "suggest" : {
    "my-suggest" : [
      {
        "text" : "jave",
        "offset" : 0,
        "length" : 4,
        "options" : [
          {
            "text" : "java",
            "score" : 0.75,
            "freq" : 1
          }
        ]
      },
      {
        "text" : "开法",
        "offset" : 4,
        "length" : 2,
        "options" : [ ]
      },
      {
        "text" : "要",
        "offset" : 6,
        "length" : 1,
        "options" : [ ]
      },
      {
        "text" : "学",
        "offset" : 7,
        "length" : 1,
        "options" : [ ]
      },
      {
        "text" : "语音",
        "offset" : 8,
        "length" : 2,
        "options" : [ ]
      },
      {
        "text" : "吗",
        "offset" : 10,
        "length" : 1,
        "options" : [ ]
      }
    ]
  }
}

2.5.10 搜索推荐

可以通过 match_phrase_prefix 匹配前缀 来达到搜索推荐的效果

GET goods/_search
{
  "query": {
    "match_phrase_prefix": {
      "name": "华为"
    }
  }
}

2.5.11 智能纠错

官方给出了几种解决方案

1. 带高亮提示的

POST goods/_search
{
  "suggest": {
    "text": "jave",
    "simple_phrase": {
      "phrase": {
        "field": "name",
        "size": 1,
        "gram_size": 3,
        "direct_generator": [ {
          "field": "name",
          "suggest_mode": "always"
        } ],
        "highlight": {
          "pre_tag": "<span color='red'>",
          "post_tag": "</span>"
        }
      }
    }
  }
}

返回结果

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 0,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "suggest" : {
    "simple_phrase" : [
      {
        "text" : "jave",
        "offset" : 0,
        "length" : 4,
        "options" : [
          {
            "text" : "ja v e java",
            "highlighted" : "ja v e <span color='red'>java</span>",
            "score" : 3.2340043E-4
          }
        ]
      }
    ]
  }
}

2. 普通的

POST goods/_search
{
  "suggest": {
    "text" : "jave",
    "simple_phrase" : {
      "phrase" : {
        "field" : "name",
        "size" : 1,
        "smoothing" : {
          "laplace" : {
            "alpha" : 0.7
          }
        }
      }
    }
  }
}

返回结果

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 0,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "suggest" : {
    "simple_phrase" : [
      {
        "text" : "jave",
        "offset" : 0,
        "length" : 4,
        "options" : [
          {
            "text" : "ja v e java",
            "score" : 8.3273224E-4
          }
        ]
      }
    ]
  }
}

复杂操作搜索 select ( 模糊查询,精准查询,排序,分页,高亮 等... !)

附、常用类型表

常用类型表

MySQL数据类型ES数据类型说明
intIntrger如果源库中的类型为unsigned int,在Elasticsearch中使用long
bigintlong
Bool
Boolean
boolean
Decimal
DEC
double如果decimal后面带小数点,为保证数据一致性,建议Elasticsearch中的数据类型使用text
doubledouble
floatfloat
CHAR
VARCHAR
longtext
text
Date
datetime
date
jsonobject如果bit只有一位,建议Elasticsearch中使用的数据类型为boolean