ElasticSearch 基本的查询命令+集成 SpringBoot

时间:2022-07-22
本文章向大家介绍ElasticSearch 基本的查询命令+集成 SpringBoot,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

关于 ElasticSearch 的安装配置请查阅这篇文章:https://blog.csdn.net/weixin_43941364/article/details/105680161

一、分词器的使用

IK 分词器的使用

最少拆分ik_smart

GET _analyze
{
  "analyzer": "ik_smart",
  "text": "中国是一个伟大的国家"
}

结果是:

{
  "tokens" : [
    {
      "token" : "中",
      "start_offset" : 0,
      "end_offset" : 1,
      "type" : "CN_CHAR",
      "position" : 0
    },
    {
      "token" : "国是",
      "start_offset" : 1,
      "end_offset" : 3,
      "type" : "CN_WORD",
      "position" : 1
    },
    {
      "token" : "一个",
      "start_offset" : 3,
      "end_offset" : 5,
      "type" : "CN_WORD",
      "position" : 2
    },
    {
      "token" : "伟大",
      "start_offset" : 5,
      "end_offset" : 7,
      "type" : "CN_WORD",
      "position" : 3
    },
    {
      "token" : "的",
      "start_offset" : 7,
      "end_offset" : 8,
      "type" : "CN_CHAR",
      "position" : 4
    },
    {
      "token" : "国家",
      "start_offset" : 8,
      "end_offset" : 10,
      "type" : "CN_WORD",
      "position" : 5
    }
  ]
}

最细粒度拆分ik_max_word

GET _analyze
{
  "analyzer": "ik_max_word",
  "text": "中国共产党"
}

查询结果:

{
  "tokens" : [
    {
      "token" : "中国共产党",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "CN_WORD",
      "position" : 0
    },
    {
      "token" : "中国",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "CN_WORD",
      "position" : 1
    },
    {
      "token" : "国共",
      "start_offset" : 1,
      "end_offset" : 3,
      "type" : "CN_WORD",
      "position" : 2
    },
    {
      "token" : "共产党",
      "start_offset" : 2,
      "end_offset" : 5,
      "type" : "CN_WORD",
      "position" : 3
    },
    {
      "token" : "共产",
      "start_offset" : 2,
      "end_offset" : 4,
      "type" : "CN_WORD",
      "position" : 4
    },
    {
      "token" : "党",
      "start_offset" : 4,
      "end_offset" : 5,
      "type" : "CN_CHAR",
      "position" : 5
    }
  ]
}

那么这些分词的依据是什么呢?

我们可以点开 ik 分词器的 config 目录查看一下字典:

其中这些 dic 就是我们的字典。

在这里可以自定义自己的词典:

要注意的是每次修改完配置项之后都要重启服务。

二、增删改查

在 ElasticSearch 中 索引相当于 数据库,type 相当于表, document 相当于一行记录,Field 相当于属性名。

1、创建与查询

PUT /test1/type1/1
{
  "name": "硕子鸽",
  "age": 18
}

执行成功,即可查看:

我们再来了解一下数据类型,这里参考官方文档 https://www.elastic.co/guide/en/elasticsearch/reference/7.7/mapping-types.html

指定字段的类型,我们只创建一个数据库索引,为他指定字段的名称和类型,即创建规则:

PUT /test2
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "age": {
        "type": "long"
      },
      "birthday": {
        "type": "date"
      }
    }
  }
}

创建成功看一下:

查询命令使用 GET

如果我们不指定字段类型呢?

在版本 7.6 及其以上版本,我们使用索引名 + _doc 创建一条记录,/test3/_doc/1,如果不指定则默认就是 _doc

也就是说 Elasticsearch 会自动识别我们的字段,然后设置合适的字段类型。

注意:keyword 为不可分割类型。

我们可以使用命令:GET _cat/indices?v 查看默认配置信息。

2、修改数据

直接使用添加数据的方法,他会覆盖原来的数据,然后在原来的版本号上 +1.

这个方法有个弊端,就是如果你漏掉了一个数据,那么这个数据就没了,要想修改一个数据,必须把原来的都带上很麻烦,我们来看一下新的方法。

使用 POST 命令:

POST /test3/_doc/1/_upodate
{
	"doc": {
		"name": "硕子弟"
	}
}

3、删除数据

删除索引:

DELETE test1

通过 DELETE 命令,根据你的命令判断,如果后面还有下一级,则会只删除下一级的数据。

三、关于文档的基本操作

通过 head 实现

使用 PUT 请求,输入demo/user/1,插入一条数据:

{
  "name": "张三",
  "age": 30,
  "desc": "这是一号同学的描述",
  "tags": [
    "标签1",
    "标签2",
    "标签3"
  ]
}

然后插入第二条数据 demo/user/2

{
  "name": "李四",
  "age": 29,
  "desc": "这是二号同学的描述",
  "tags": [
    "标签1",
    "标签2",
    "标签3"
  ]
}

第三条 demo/user/3

{
  "name": "王五",
  "age": 28,
  "desc": "这是三号同学的描述",
  "tags": [
    "标签1",
    "标签2",
    "标签3"
  ]
}

如果要查询的话,发送 GET 请求,就是简单的条件查询:

demo/user/1

这是最简单的根据 ID 查询,那稍微复杂一点的查询呢?

demo/user/_search?q=name:张三

如果使用这个:

demo/user/_search?q=desc:同学

他会把所有的描述信息带有同学的记录都查询出来,这个时候就体现出来搜索了。

可以看到上面的返回数据中有一个 score 字段,这个字段的含义就是权重的意思。

我们也可以使用下面的这个查询:

demo/user/_search GET

{
  "query": {
    "match": {
      "name": "李四"
    }
  }
}

也会得到相同的结果。

通过 Kibana 实现

我们使用 Kibana 来操作一下:

首先创建数据:

PUT /test2/_doc/1
{
  "name": "张三",
  "age": 18,
  "desc": "像一个菜鸡",
  "tags": [
      "憨批", "菜鸡", "蒟蒻"
    ]
}


PUT /test2/_doc/2
{
  "name": "李四",
  "age": 19,
  "desc": "像2个菜鸡",
  "tags": [
      "憨批1", "菜鸡1", "蒟蒻1"
    ]
}

PUT /test2/_doc/3
{
  "name": "王五",
  "age": 20,
  "desc": "像3个菜鸡",
  "tags": [
      "憨批2", "菜鸡2", "蒟蒻2"
    ]
}

然后修改数据

POST /test2/_doc/1/_update
{
  "doc": {
    "desc": "菜鸡可不是我"
  }
}

POST /test2/_doc/3/_update
{
  "doc": {
    "desc": "我是猪"
  }
}

然后查询数据:

GET test2/_search?q=name:张三;
GET test2/_search?q=desc:猪;

get test2/_search
{
  "query": {
    "match": {
      "name": "张三"
    }
  }
}

返回结果为:

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 2.0996442,
    "hits" : [
      {
        "_index" : "test2",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 2.0996442,
        "_source" : {
          "name" : "张三",
          "age" : 18,
          "desc" : "菜鸡可不是我",
          "tags" : [
            "憨批",
            "菜鸡",
            "蒟蒻"
          ]
        }
      }
    ]
  }
}
  • hits:索引和文档信息,查询出来的是具体的文档;
  • _score:通过分数来判断最佳匹配;

复杂查询

只想要指定的字段:

GET test2/_search
{
  "query": {
    "match": {
      "name": "张三"
    }
  },
  "_source": ["name", "desc"]
}

只查出 name 和 sesc;

"hits" : [
      {
        "_index" : "test2",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.6533571,
        "_source" : {
          "name" : "张三",
          "desc" : "菜鸡可不是我"
        }
      }
]

排序

使用 sort

GET test2/_search
{
  "query": {
    "match": {
      "desc": "菜鸡"
    }
  },
  "sort": [
    {
      "age": {
        "order": "asc"
      }
    }
  ]
}

分页

  • from:从第几个数据开始;
  • size:每页的个数;
GET test2/_search
{
  "query": {
    "match": {
      "desc": "菜鸡"
    }
  },
  "sort": [
    {
      "age": {
        "order": "asc"
      }
    }
  ],
  "from": 0, 
  "size": 2
}

返回布尔值

GET test2/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "张三"
          }
        },
        {
          "match": {
            "age": "18"
          }
        }
      ]
    }
  }
}
  • must:所有的条件都要符合;
  • shoulder:两个条件满足其一就行。
  • must_not:结果取反;

过滤器

GET test2/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "张三"
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "gte": 10,
            "lte": 20
          }
        }
      }
    }
  }
}
  • filter:过滤选项;
  • gte:大于等于;
  • lte:小于等于;
  • gt:大于;
  • lt:小于。

匹配多个条件

直接使用空格隔开:

GET test2/_search
{
  "query": {
    "match": {
      "tags": "菜鸡 憨批"
    }
  }
}

精确查询

  • term:直接查询精确的;
  • match:会使用分词器,先分析文档,然后在通过分析文档进行查询;

两个类型

  • text:会被分词器解析;
  • keyword:不会被分词器解析;

严格的查询年龄是 18 岁的人:

GET test2/_search
{
  "query": {
    "term": {
      "age": 18
    }
  }
}

高亮查询

GET test2/_search
{
  "query": {
    "match": {
      "name": "张三"
    }
  },
  "highlight": {
    "fields": {
      "name": {}
    }
  }
}

查询结果:

"hits" : [
  {
    "_index" : "test2",
    "_type" : "_doc",
    "_id" : "1",
    "_score" : 1.6533571,
    "_source" : {
      "name" : "张三",
      "age" : 18,
      "desc" : "菜鸡可不是我",
      "tags" : [
        "憨批",
        "菜鸡",
        "蒟蒻"
      ]
    },
    "highlight" : {
      "name" : [
        "<em>张</em><em>三</em>"
      ]
    }
  }
]