11. 好客租房-ElasticSearch入门学习

news2025/1/11 6:50:23

Elaticsearch,简称为es, es是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据。

es也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。

11.1 ES简介与安装

es使用java开发,使用lucene作为核心,需要配置好java环境!

使用docker安装教程如下:

#拉取镜像
docker pull elasticsearch:6.5.4
#创建并启动镜像
docker run --name elasticsearch -d -e ES_JAVA_OPTS="-Xms512m -Xmx512m" -e "discovery.type=single-node" -p 9200:9200 -p 9300:9300 elasticsearch:6.5.4

#参数说明如下:
# --name表示镜像启动后的容器名称  
# -d: 后台运行容器,并返回容器ID;
# -e: 指定容器内的环境变量
# -p: 指定端口映射,格式为:主机(宿主)端口:容器端口

然后打开浏览器访问ip:9200 如果出现以下界面就是安装成功

11.2 ES-head简介与安装

由于ES官方并没有为ES提供界面管理工具,仅仅是提供了后台的服务。

elasticsearch-head是一个为ES开发的一个页面客户端工具,其源码托管于GitHub,地址为:https://github.com/mobz/elasticsearch-head

我们这里提供docker安装方式:

#拉取镜像
docker pull mobz/elasticsearch-head:5
#创建容器
docker create --name elasticsearch-head -p 9100:9100 mobz/elasticsearch-head:5
#启动容器
docker start elasticsearch-head

通过浏览器进行访问ip:9100(看到的内容稍有不同, 建议再往下看一下):

尝试连接easticsearch会发现无法连接上,由于是前后端分离开发,所以会存在跨域问题,需要在服务端做CORS的配置。

需要修改ES的配置文件:

docker exec -it elasticsearch /bin/bash (进不去使用容器id进入)

vi config/elasticsearch.yml

添加内容如下:

http.cors.enabled: true 
http.cors.allow-origin: "*"

然后重启ES项目即可

exit
docker restart 容器id

接下来你可以尝试通过ES-head对ES做一些操作, 比如:新增一个索引, 你会发现没啥反应, 打开F12会有406错误.

需要你修改ES-head的配置文件

#复制vendor.js到外部
docker cp {ES-head的容器id}:/usr/src/app/_site/vendor.js /usr/local/

#修改vendor.js, 修改内容在下面
vim vendor.js

#修改内容:
1. 通过:6886跳转到6886行(vim的跳转固定行数命令:rowNum), 修改其中的"application/x-www-form-unlencoded" 为
"application/json;charset=UTF-8"

2.通过:7574跳转到7574行, 同样的修改:
"application/x-www-form-unlencoded" 修改为
"application/json;charset=UTF-8"

#修改结束


# 修改完成后
docker cp /usr/local/vendor.js  {ES-head的容器id}:/usr/src/app/_site
# 重启ES-head
docker restart 容器id

11.3 ES 基本概念入门

主要可以分为:索引,文档, 映射,文档类型四个部分

ES中的概念

MySQL中的概念

映射关系(备注)

_index(索引)

table(表)

索引(index)是Elasticsearch对逻辑数据的逻辑存储,

这一点与MySQL中的Table一致

document(文档)

row(行)

存储在Elasticsearch中的主要实体叫文档 一个文档相当于数据库表中的一行记录。 不同点:ES的文档可以有多种结构, 但是字段名相同时, 字段类型必须一致 你可以理解为一个有很多很多固定列的表. 没用到的列对于当前行都是不存在.

mapping(映射)

无对应

所有文档写进索引之前都会先进行分析 如何将输入的文本分割为词条、哪些词条又会被过滤,这种行为叫做映射 一般由用户自己定义规则。

文档类型

类似json对象的类型

在ES中,一个索引对象可以存储很多不同用途的对象。 例如,一个博客应用程序可以保存文章和评论。 不同的文档类型不能为相同的属性设置不同的类型。 例如,文章和评论存储在同一个索引中时,叫title的字段必须具有相同的类型。

概念看起来很乏味, 只需要记住索引对应的是表, 文档对应的是行, 其他的我们在接下来的实战中学习.

11.4 ES的RESTful API实战样例.

在Elasticsearch中,提供了丰富的RESTful API的操作,包括基本的CRUD、创建索引、删除索引等操作。

11.4.1 新建索引操作

先打开ES-head, ip:9100,然后在网页最上面的输入框输入ES的ip:9200, 连接, 连接成功后->索引->新建索引->新建一个名称为test的索引, 分片数为2,副本数为0,注意点ok前需要打开F12的网络.

testIdx会报错400, 因为索引名称必须全小写, 所以索引名称改成test.

创建成功后观察网络:

会发现它里面发出了若干个请求, 主要观察下第二个, 你会发现其发出的内容基本就是如下请求:

PUT http://{ES的ip}:9200/test

# 下面这段json是put的请求体的内容:
{
    "settings": {
        "index": {
            "number_of_shards": "2", #分片数(注释需要删掉哦)
            "number_of_replicas": "0" #副本数(注释需要删掉哦)
        }
    }
}
#注意http请求头里必须有这个key-value
Content-Type:application/json;charset=UTF-8

我们可以自己在浏览器打开一个Http请求插件, 按照上面要求输入,把test改成haok, 不然会报错索引已存在:

打开es-head查看, 确实多了一个索引:

11.4.2 删除索引操作

#删除索引
DELETE http://{ES的ip}:9200/haok

# 返回结果如下
{
    "acknowledged": true
}

查看ES-head, 删除成功了.

11.4.3 插入数据

URL规则:
POST http://ip:9200/{索引}/{类型}/{id}
POST http://ip:9200/test/user/1001
# 解释: test是我们一开始建的索引, user是一个类型, 在第一次插入数据时会自动创建, 1001是指定主键的值

#请求体数据如下:
{
    "id":1001,
    "name":"张三",
    "age":20,
    "sex":"男"
}

#响应内容:
{
    "_index": "haoke",
    "_type": "user",
    "_id": "1",
    "_version": 1,
    "result": "created",
    "_shards": {
        "total": 1,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 0,
    "_primary_term": 1
}

插入后,查看内容:

然后我们再试试不指定id的插入,观察下_id的值.

POST http://ip:9200/test/user
# 不指定id

#请求体数据如下:
{
    "id":1002,
    "name":"张三",
    "age":20,
    "sex":"男"
}

查看ES-head

可以看到_id是随机生成的一个字符串.

11.4.4 更新数据

更新数据本质上是覆盖数据:

PUT http://ip:9200/test/user/1001
{
    "id":1001,
    "name":"张三",
    "age":21,
    "sex":"女" 
}
#你可以删掉一个属性, 会发现被删除的属性也丢失了.

#响应体:
{
  "_index": "test",
  "_type": "user",
  "_id": "1001",
  "_version": 2, # 注意版本号更新了, 从1->2
  "result": "updated",
  "_shards": {
    "total": 1,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 2,
  "_primary_term": 1
}

当然, ES也支持局部属性更新, 不过底层仍然是取出修改部分,然后覆盖.

局部更新代码:

#注意:这里多了_update标识
POST http://ip:9200/test/user/1001/_update
{
    "doc":{
        "age":23
    }
}

#相应里版本号会再加一, ES中也只更新了age

11.4.5 删除数据

DELETE http://ip:9200/test/user/1001

#响应内容:
{
  "_index": "test",
  "_type": "user",
  "_id": "1001",
  "_version": 4, #删除版本号也会增加
  "result": "deleted",
  "_shards": {
    "total": 1,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 4,
  "_primary_term": 1
}

#如果删除一条不存在的数据,会响应404:
DELETE http://ip:9200/test/user/10011

报错404

删除一个文档也不会立即从磁盘上移除,它只是被标记成已删除。Elasticsearch将会在你之后添加更多索引
的时候才会在后台进行删除内容的清理。

11.4.6 查询数据

GET http://ip:9200/haoke/user/BbPe_WcB9cFOnF3uebvr
# BbPe_WcB9cFOnF3uebvr是我的1002的_id, 你需要根据你自己的1002的_id替换

#响应内容
{
    "_index":"test",
    "_type":"user",
    "_id":"PaGkXIQBtVAmf7zP8htb",
    "_version":1,
    "found":true,
    "_source":{
		"id":1002,
        "name":"张三",
        "age":20,
        "sex":"男"
	}
}
搜索全部数据
#在搜索前, 我们手动插入两条数据
PUT http://ip:9200/test/user/1003
{
    "id":1003,
    "name":"李四",
    "age":20,
    "sex":"男"
}

PUT http://ip:9200/test/user/1004
{
    "id":1004,
    "name":"王五",
    "age":20,
    "sex":"男"
}

#获取全部数据
GET http://ip:9200/test/user/_search

#响应内容:
{
  "took": 1,
  "timed_out": false,
  "_shards": { "total": 2, "successful": 2, "skipped": 0, "failed": 0 },
  "hits": {
    "total": 3,
    "max_score": 1.0,
    "hits": [
      {
        "_index": "test",
        "_type": "user",
        "_id": "PaGkXIQBtVAmf7zP8htb",
        "_score": 1.0,
        "_source": {
          "id": 1002,
          "name": "张三",
          "age": 20,
          "sex": "男"
        }
      },
      {
        "_index": "test",
        "_type": "user",
        "_id": "1003",
        "_score": 1.0,
        "_source": {
          "id": 1003,
          "name": "李四",
          "age": 20,
          "sex": "男"
        }
      },
      {
        "_index": "test",
        "_type": "user",
        "_id": "1004",
        "_score": 1.0,
        "_source": {
          "id": 1004,
          "name": "王五",
          "age": 20,
          "sex": "男"
        }
      }
    ]
  }
}
关键字搜素数据
#查询年龄等于20的用户
GET http://ip:9200/test/user/_search?q=age:20

11.4.7 DSL 搜索

Elasticsearch提供丰富且灵活的查询语言叫做DSL查询(Query DSL),它允许你构建更加复杂、强大的查询。

DSL(Domain Specific Language特定领域语言)以JSON请求体的形式出现

POST http://ip:9200/test/user/_search
#请求体
{
    "query" : {
        "match" : { 
            "id" : 1002
        }
    }
}

#响应:
{
  "took": 6,
  "timed_out": false,
  "_shards": { "total": 2, "successful": 2, "skipped": 0, "failed": 0 },
  "hits": {
    "total": 1,
    "max_score": 1.0,
    "hits": [
      {
        "_index": "test",
        "_type": "user",
        "_id": "PaGkXIQBtVAmf7zP8htb",
        "_score": 1.0,
        "_source": {
          "id": 1002,
          "name": "张三",
          "age": 20,
          "sex": "男"
        }
      }
    ]
  }
}
查询id小于1004的男性
POST http://ip:9200/test/user/_search
#请求数据
{
  "query": {
    "bool": {
      "filter": {
        "range": {
          "id": {
            "lt": 1004
          }
        }
      },
      "must": {
        "match": {
          "sex": "男"
        }
      }
    }
  }
}

#响应
{
    "took": 5,
    "timed_out": false,
    "_shards": {
        "total": 2,
        "successful": 2,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 2,
        "max_score": 0.13353139,
        "hits": [
            {
                "_index": "test",
                "_type": "user",
                "_id": "PaGkXIQBtVAmf7zP8htb",
                "_score": 0.13353139,
                "_source": {
                    "id": 1002,
                    "name": "张三",
                    "age": 20,
                    "sex": "男"
                }
            },
            {
                "_index": "test",
                "_type": "user",
                "_id": "1003",
                "_score": 0.13353139,
                "_source": {
                    "id": 1003,
                    "name": "李四",
                    "age": 20,
                    "sex": "男"
                }
            }
        ]
    }
}
POST http://ip:9200/haoke/user/_search
#请求数据
{
    "query": {
        "match": {
        	"name": "张三 李四"
        }
    }
}
# 查询name = 张三 || name = 李四

11.5 ES常见高级操作

11.5.1 文档

在之前的概念入门中提到, ES的文档 ≈ 数据库表中的一行记录, 而在ES中存储文档的格式为json. 而json是支持嵌套对象的.

{
    "_index": "test",
    "_type": "user",
    "_id": "1005",
    "_version": 1,
    "_score": 1,
    "_source": {
        "id": 1005,
        "name": "孙七",
        "age": 37,
        "sex": "女",
        "card": {
            "card_number": "123456789" # 本行为重点
        }
    }
}

在学习查询的时候, 我们还看到了每次请求返回的内容都有一些通用的值, 其中如下这三个被称为"元数据"

    "_index": "haoke", # 文档存储的地方,      就是数据库中其所在的DB
    "_type": "user",   # 文档代表的对象的类    就是数据库中其所属的Table
    "_id": "1005",     # 文档的唯一标识,       就是数据库中的主键.
可以在查询url后面添加pretty参数,使得返回的json更易查看。
比如
POST http://ip:9200/haoke/user/_search?pretty

11.5.2 指定响应字段

在响应的数据中,如果我们不需要全部的字段,可以指定某些需要的字段进行返回。

GET http://ip:9200/test/user/1003?_source=id,name

#返回值如下:
{
  "_index": "test",
  "_type": "user",
  "_id": "1003",
  "_version": 1,
  "found": true,
  "_source": {
    "name": "李四", # 只有id和name属性
    "id": 1003
  }
}

如不需要返回元数据,仅仅返回原始数据,可以这样:

GET http://ip:9200/haoke/user/1003/_source

#响应如下:  响应中不再有元数据
{
  "id": 1003,
  "name": "李四",
  "age": 20,
  "sex": "男"
}

当然, 上面两种可以一起用

GET http://ip:9200/haoke/user/1003/_source?_source=id,name

#响应如下:  响应中不再有元数据,并且只有选定的属性答应
{
  "name": "李四",
  "id": 1003
}

11.5.3 判断文档是否存在

HEAD http://ip:9200/haoke/user/1005
# 当前存在时响应状态为200
# 当前不存在时响应状态为404

11.5.4 批量查询

POST http://ip:9200/haoke/user/_mget
#请求体:
{
    "ids" : [ "1001", "1003" ]
}

# 输出内容如下:
{
	"docs": [{
		"_index": "test",
		"_type": "user",
		"_id": "1004",
		"_version": 1,
		"found": true,
		"_source": {
			"id": 1004,
			"name": "王五",
			"age": 20,
			"sex": "男"
		}
	}, {
		"_index": "test",
		"_type": "user",
		"_id": "1003",
		"_version": 1,
		"found": true,
		"_source": {
			"id": 1003,
			"name": "李四",
			"age": 20,
			"sex": "男"
		}
	}]
}

11.5.5 分页

和SQL使用LIMIT 关键字返回只有一页的结果一样,Elasticsearch接受from 和size 参数:

GET /_search?size=5				 # 默认从idx=0  开始查, size=5
GET /_search?size=5&from=5		 # 默认从idx=5  开始查, size=5
GET /_search?size=5&from=10		 # 默认从idx=10 开始查, size=5
ES支持分布式, 这就意味着如果你请求排序后的前一千个对象, 那么每台机器都会查出排序好的前一千个, 然后汇总到 请求节点, 再进行排序, 最后才将真正的前1000个返回.

11.6 分词与中文分词

分词就是指将一个文本转化成一系列单词的过程,也叫文本分析,在Elasticsearch中称之为Analysis。

举例:我是中国人 --> 我/是/中国人

POST http://ip:9200/_analyze
# 请求体
{
    "analyzer":"standard", # 我在这里使用的是标准分词器。
    "text":"hello world"
}

#输出:
{
	"tokens": [{
		"token": "hello",  #分词第一个:hello
		"start_offset": 0,
		"end_offset": 5,
		"type": "<ALPHANUM>",
		"position": 0
	}, {
		"token": "world", #分词第一个:world
		"start_offset": 6,
		"end_offset": 11,
		"type": "<ALPHANUM>",
		"position": 1
	}]
}

那么如果分词中文能得到我们想要的结果吗?

# 使用标准分词器分析‘你好世界’
{
	"tokens": [{
		"token": "你",
		"start_offset": 0,
		"end_offset": 1,
		"type": "<IDEOGRAPHIC>",
		"position": 0
	}, {
		"token": "好",
		"start_offset": 1,
		"end_offset": 2,
		"type": "<IDEOGRAPHIC>",
		"position": 1
	}, {
		"token": "世",
		"start_offset": 2,
		"end_offset": 3,
		"type": "<IDEOGRAPHIC>",
		"position": 2
	}, {
		"token": "界",
		"start_offset": 3,
		"end_offset": 4,
		"type": "<IDEOGRAPHIC>",
		"position": 3
	}]
}

这个效果肯定不对的。 这是因为ES的标准分词器不支持中文, 所以我们就需要自已安装一个支持中文的分词器。

常用中文分词器,IK、jieba、THULAC等,推荐使用IK分词器。

#安装方法:将下载到的elasticsearch-analysis-ik-6.5.4.zip解压到/elasticsearch/plugins/ik
目录下即可。
#如果使用docker运行
docker cp /tmp/elasticsearch-analysis-ik-6.5.4.zip
elasticsearch:/usr/share/elasticsearch/plugins/
#进入容器
docker exec -it elasticsearch /bin/bash
mkdir /usr/share/elasticsearch/plugins/ik
cd /usr/share/elasticsearch/plugins/ik
unzip elasticsearch-analysis-ik-6.5.4.zip
#重启容器即可
docker restart elasticsearch

再次测试

POST http://172.16.55.185:9200/_analyze
{
    "analyzer": "ik_max_word",
    "text": "我是中国人"
}
# 输出如下:
{
	"tokens": [{
		"token": "你好",
		"start_offset": 0,
		"end_offset": 2,
		"type": "CN_WORD",
		"position": 0
	}, {
		"token": "世界",
		"start_offset": 2,
		"end_offset": 4,
		"type": "CN_WORD",
		"position": 1
	}]
}

11.7 全文搜索

11.7.1 倒排索引

在介绍倒排索引之前, 先说一下"正排索引".

我们搜索一篇文章是否有某个关键字, 最常见的sql语句就是like

-- 搜索博客的文章标题或者内容中包含'测试'
SELECT * FROM blog WHERE title LIKE '%测试%' OR content LIKE '%测试%' 

这个思路就是正排, 我们去所有的文章的标题和内容中寻找.

如果有1000w篇3000字的文章, 效率怎么样? 自然是非常非常慢了.

一般我们使用常见的汉字只有5000个, 加上常见的生僻字也就一万两千个, 所以换一种思路, 不是去文章找词, 而是在添加一篇文章到数据库里, 将文章编号与其中所有的词关联.

编号

单词

文章编号(使用'->'拼接多个文章编号)

1

你好

1->3->1102

2

世界

1->1101

3

测试

2

那么,我们搜索'你好'的时候, 很快就定位到了编号为1,3,1102的文章.

实际上, 我们这里的文章编号的结构往往更复杂.

1->3->1102

我们判断词与文章的关联度往往需要该词在文中出现的次数

比如: (1, 3)->(3, 1)->(1102, 2);
其中(1,3)就是编号为1的文章中单词出现了三次

此外, 我们在搜索引擎中搜东西, 还会告诉你该词在文中的上下文, 这就需要我们记录单词出现的下标了.

(1, 3,[11, 17, 53])->(3, 1[22])->(1102, 2[101, 188]);
其中(1,3,[11, 17, 53])就是编号为1的文章中单词出现了三次, 位置分别是idx = 11,idx = 17,idx = 53

全文搜索两个最重要的方面是:

相关性(Relevance) 它是评价查询与其结果间的相关程度,并根据这种相关程度对结果排名的一种能力,这种计算方式可以是 TF/IDF 方法、地理位置邻近、模糊相似,或其他的某些算法。

分析(Analysis) 它是将文本块转换为有区别的、规范化的 token 的一个过程,目的是为了创建倒排索引以及查询倒排索引。

11.7.2 构造数据

PUT http://172.16.55.185:9200/itcast
# 构建分片索引和类型,指定类型的属性的类型, 注意我们指定了hobby的分词器是ik,所以支持分词且支持中文分词
{
    "settings": {
        "index": {
            "number_of_shards": "1",
            "number_of_replicas": "0"
        }
    },
   "mappings": {
        "person": {
            "properties": {
                "name": {
                    "type": "text"
                },
                "age": {
                    "type": "integer"
                },
                "mail": {
                    "type": "keyword"
                },
                "hobby": {
                    "type": "text",
                    "analyzer":"ik_max_word"
                }
            }
        }
    }
}

插入数据

POST http://ip:9200/itcast/_bulk
#批量插入操作, 注意hobby会被ik分词器解析
{"index":{"_index":"itcast","_type":"person"}}
{"name":"张三","age": 20,"mail": "111@qq.com","hobby":"羽毛球、乒乓球、足球"}
{"index":{"_index":"itcast","_type":"person"}}
{"name":"李四","age": 21,"mail": "222@qq.com","hobby":"羽毛球、乒乓球、足球、篮球"}
{"index":{"_index":"itcast","_type":"person"}}
{"name":"王五","age": 22,"mail": "333@qq.com","hobby":"羽毛球、篮球、游泳、听音乐"}
{"index":{"_index":"itcast","_type":"person"}}
{"name":"赵六","age": 23,"mail": "444@qq.com","hobby":"跑步、游泳、篮球"}
{"index":{"_index":"itcast","_type":"person"}}
{"name":"孙七","age": 24,"mail": "555@qq.com","hobby":"听音乐、看电影、羽毛球"}

然后响应是200, 就去ip:9100看看数据.

11.7.3 单词搜索实战

POST http://ip:9200/itcast/person/_search
# ES使用倒排索引查询hobby(爱好)中包含'音乐'的文档, 并且在hobby中高亮
{
    "query":{
        "match":{
            "hobby":"音乐"
        }
    },
    "highlight": {
        "fields": {
            "hobby": {}
    	}
    }
}

# 响应内容
{
	"took": 9,
	"timed_out": false,
	"_shards": {
		"total": 1,
		"successful": 1,
		"skipped": 0,
		"failed": 0
	},
	"hits": {
		"total": 2,
		"max_score": 0.6841192,
		"hits": [{
				"_index": "itcast",
				"_type": "person",
				"_id": "Uv0cDWgBR-bSw8-LpdkZ",
				"_score": 0.6841192,
				"_source": {
					"name": "王五",
					"age": 22,
					"mail": "333@qq.com",
					"hobby": "羽毛球、篮球、游泳、听音乐"
				},
				"highlight": {
					"hobby": [
						"羽毛球、篮球、游泳、听<em>音乐</em>"
					]
				}
			},
			{
				"_index": "itcast",
				"_type": "person",
				"_id": "VP0cDWgBR-bSw8-LpdkZ",
				"_score": 0.6841192,
				"_source": {
					"name": "孙七",
					"age": 24,
					"mail": "555@qq.com",
					"hobby": "听音乐、看电影、羽毛球"
				},
				"highlight": {
					"hobby": [
						"听<em>音乐</em>、看电影、羽毛球"
					]
				}
			}
		]
	}
}

如果你认真观察上文的输出的话, 你会看到每一个查出来的person不仅有元数据和版本, 还有一个之前没见过的属性_score

"_score": 0.6841192

这个属性就是我们前面提到的相关性的数值化. 这个值就是根据词频反向文档频率字段总长度计算得出

词频: term frequency,即词 “音乐” 在相关文档的hobby 字段中出现的频率
反向文档频率: inverse document frequency,即词 “音乐” 在所有文档的hobby 字段中出现的频率
字段的长度 : 即字段越短相关度越高

11.7.4 多词搜索

我们接下来搜索爱好"音乐和篮球"

POST http://ip:9200/itcast/person/_search
# 查询hobby中包含音乐或者篮球的词, 并高亮
{
    "query":{
        "match":{
        	"hobby":"音乐 篮球"
        }
    },
    "highlight": {
        "fields": {
      		"hobby": {}
        }
    }
}
# 输出如下:
{
	"took": 22,
	"timed_out": false,
	"_shards": {
		"total": 1,
		"successful": 1,
		"skipped": 0,
		"failed": 0
	},
	"hits": {
		"total": 4,
		"max_score": 1.3192271,
		"hits": [{
			"_index": "itcast",
			"_type": "person",
			"_id": "QKFJe4QBtVAmf7zPsxuE",
			"_score": 1.3192271,
			"highlight": {
				"hobby": ["羽毛球、<em>篮球</em>、游泳、听<em>音乐</em>"]
			}
		}, {
			"_index": "itcast",
			"_type": "person",
			"_id": "QqFJe4QBtVAmf7zPsxuE",
			"_score": 0.81652206,
			"highlight": {
				"hobby": ["听<em>音乐</em>、看电影、羽毛球"]
			}
		}, {
			"_index": "itcast",
			"_type": "person",
			"_id": "QaFJe4QBtVAmf7zPsxuE",
			"_score": 0.6987338,
			"highlight": {
				"hobby": ["跑步、游泳、<em>篮球</em>"]
			}
		}, {
			"_index": "itcast",
			"_type": "person",
			"_id": "P6FJe4QBtVAmf7zPsxuE",
			"_score": 0.50270504,
			"highlight": {
				"hobby": ["羽毛球、乒乓球、足球、<em>篮球</em>"]
			}
		}]
	}
}

结果明显是或的查询, 说明如果不指定默认查询的是分词后的或的关系.

# 在上一个查询的基础上, 我们在hobby搜索条件里加上 "operator":"and", 这样就可以按且的关系查询了.
{
	"query": {
		"match": {
			"hobby": {
				"query": "音乐 篮球",
				"operator": "and"
			}
		}
	},
	"highlight": {
		"fields": {
			"hobby": {}
		}
	}
}

# 查询结果
{
	"took": 5,
	"timed_out": false,
	"_shards": {
		"total": 1,
		"successful": 1,
		"skipped": 0,
		"failed": 0
	},
	"hits": {
		"total": 1,
		"max_score": 1.3192271,
		"hits": [{
			"_index": "itcast",
			"_type": "person",
			"_id": "QKFJe4QBtVAmf7zPsxuE",
			"_score": 1.3192271,
			"highlight": {
				"hobby": ["羽毛球、<em>篮球</em>、游泳、听<em>音乐</em>"]
			}
		}]
	}
}

11.7.5 组合搜索

POST http://172.16.55.185:9200/itcast/person/_search
# 必须包含'篮球', 不能包含'音乐',包含了'游泳'的话权重更高.
{
    "_source": false,
	"query": {
		"bool": {
			"must": {
				"match": {
					"hobby": "篮球"
				}
			},
			"must_not": {
				"match": {
					"hobby": "音乐"
				}
			},
			"should": [{
				"match": {
					"hobby": "游泳"
				}
			}]
		}
	},
	"highlight": {
		"fields": {
			"hobby": {}
		}
	}
}

#响应内容
{
	"took": 13,
	"timed_out": false,
	"_shards": {
		"total": 1,
		"successful": 1,
		"skipped": 0,
		"failed": 0
	},
	"hits": {
		"total": 2,
		"max_score": 1.8336569,
		"hits": [{
			"_index": "itcast",
			"_type": "person",
			"_id": "QaFJe4QBtVAmf7zPsxuE",
			"_score": 1.8336569,
			"highlight": {
				"hobby": ["跑步、<em>游泳</em>、<em>篮球</em>"]
			}
		}, {
			"_index": "itcast",
			"_type": "person",
			"_id": "P6FJe4QBtVAmf7zPsxuE",
			"_score": 0.50270504,
			"highlight": {
				"hobby": ["羽毛球、乒乓球、足球、<em>篮球</em>"]
			}
		}]
	}
}

11.7.6 权重

有些时候,我们可能需要对某些词增加权重来影响该条数据的得分。如下:

搜索关键字为“游泳篮球”,如果结果中包含了“音乐”权重为10,包含了“跑步”权重为2
POST http://ip:9200/itcast/person/_search
{
	"query": {
		"bool": {
			"must": {
				"match": {
					"hobby": {
						"query": "游泳 篮球",
						"operator": "and"
					}
				}
			},
			"should": [{
					"match": {
						"hobby": {
							"query": "音乐",
							"boost": 10
						}
					}
				},
				{
					"match": {
						"hobby": {
							"query": "跑步",
							"boost": 2
						}
					}
				}
			]
		}
	},
	"highlight": {
		"fields": {
			"hobby": {}
		}
	}
}

#响应内容:
{
	"took": 4,
	"timed_out": false,
	"_shards": {
		"total": 1,
		"successful": 1,
		"skipped": 0,
		"failed": 0
	},
	"hits": {
		"total": 2,
		"max_score": 9.484448,
		"hits": [{
			"_index": "itcast",
			"_type": "person",
			"_id": "QKFJe4QBtVAmf7zPsxuE",
			"_score": 9.484448,
			"_source": {
				"name": "王五",
				"age": 22,
				"mail": "333@qq.com",
				"hobby": "羽毛球、篮球、游泳、听音乐"
			},
			"highlight": {
				"hobby": ["羽毛球、<em>篮球</em>、<em>游泳</em>、听<em>音乐</em>"]
			}
		}, {
			"_index": "itcast",
			"_type": "person",
			"_id": "QaFJe4QBtVAmf7zPsxuE",
			"_score": 5.4279313,
			"_source": {
				"name": "赵六",
				"age": 23,
				"mail": "444@qq.com",
				"hobby": "跑步、游泳、篮球"
			},
			"highlight": {
				"hobby": ["<em>跑步</em>、<em>游泳</em>、<em>篮球</em>"]
			}
		}]
	}
}

11.7.7 短语匹配

在Elasticsearch中,短语匹配意味着不仅仅是词要匹配,并且词的顺序也要一致,如下:

POST http://172.16.55.185:9200/itcast/person/_search
{
    "query":{
        "match_phrase":{
            "hobby":{
            	"query":"羽毛球篮球"
            }
        }
    },
    "highlight": {
        "fields": {
        	"hobby": {}
        }
    }
}

# 返回内容:
{
	"took": 43,
	"timed_out": false,
	"_shards": {
		"total": 1,
		"successful": 1,
		"skipped": 0,
		"failed": 0
	},
	"hits": {
		"total": 1,
		"max_score": 1.307641,
		"hits": [{
			"_index": "itcast",
			"_type": "person",
			"_id": "QKFJe4QBtVAmf7zPsxuE",
			"_score": 1.307641,
			"_source": {
				"name": "王五",
				"age": 22,
				"mail": "333@qq.com",
				"hobby": "羽毛球、篮球、游泳、听音乐"
			},
			"highlight": {
				"hobby": ["<em>羽毛</em><em>球</em>、<em>篮球</em>、游泳、听音乐"]
			}
		}]
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/179535.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分享144个ASP源码,总有一款适合您

ASP源码 分享144个ASP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 144个ASP源码下载链接&#xff1a;https://pan.baidu.com/s/15O9p6a8XlNN0u-wFKEkJqQ?pwd8354 提取码&#x…

Go 语言

Go语言是云计算时代的语言 Go语言2007年诞生于Google&#xff0c;2009年开源&#xff0c;Go语言与区块链技术一样年轻 本文是对Go语言基本语法的总结 目录 Go词法单元 token Go的token 标识符 内置数据类型标识符 常量值标识符 空白标识符 关键字 程序整体结构的关键字…

VBA提高篇_05日期时间函数

文章目录日期函数1. Date()2. Time()3. Now()时间数据解析函数时间运算函数DateDiff() 数据时间差DateAdd() 时间点指定跨越拓展日期函数 VBA中默认日期系统格式: #1/26/2023 12:20:25 # #月/日/年 时:分:秒# 1. Date() 获取当前系统的时间(年/月/日) 精度: 精确到秒 范围: 公…

Tomcat-HTTP服务器介绍、安装与使用

文章目录一、概述二、下载安装三、介绍四、启动Tomcat一、概述 Tomcat&#xff0c;是一个 HTTP 服务器&#xff0c;就是在 TCP 服务器的基础上&#xff0c;加上了一些额外的功能。使用 HTTP 服务器的 API。就可以来提取HTTP请求的内容&#xff0c;也可以构造HTTP响应 二、下载…

【GPLT 二阶题目集】L2-015 互评成绩

学生互评作业的简单规则是这样定的&#xff1a;每个人的作业会被k个同学评审&#xff0c;得到k个成绩。系统需要去掉一个最高分和一个最低分&#xff0c;将剩下的分数取平均&#xff0c;就得到这个学生的最后成绩。本题就要求你编写这个互评系统的算分模块。 输入格式&#xff…

HBase原理和设计

简介 HBase —— Hadoop Database的简称&#xff0c;Google BigTable的另一种开源实现方式&#xff0c;从问世之初&#xff0c;就为了解决用大量廉价的机器高速存取海量数据、实现数据分布式存储提供可靠的方案。从功能上来讲&#xff0c;HBase不折不扣是一个数据库&#xff0…

EcoStruxure Operator Terminal Expert 操作员终端专家

EcoStruxure Operator Terminal Expert&#xff08;以前称为 Vijeo XD&#xff09;是一款具有最新 UI 设计和手势的触摸屏配置软件&#xff0c;使您能够为 Magelis HMI 和 iPC 创建和编辑应用程序屏幕。 特点&#xff1a; 变量——内存中用于存储数据的命名空间。创建您需要的所…

MS-Model【3】:Medical Transformer

文章目录前言1. Abstract & Introduction1.1. Abstract1.2. Introduction2. Medical Transformer (MedT)2.1. Model structure2.2. Attention2.2.1. Self-Attention Overview2.2.2. Axial-Attention2.2.3. Gated Axial-Attention2.3. Local-Global Training2.4. Loss funct…

定位 position属性 相对定位 绝对定位 固定定位 定位下的居中 多个定位元素重叠时 补充

目录定位position属性相对定位绝对定位固定定位定位的做法&#xff1a; 定位下的居中多个定位元素重叠时补充定位 视觉格式化模型&#xff0c;大体上将页面中盒子的排列分为三种方式&#xff1a; 常规流浮动&#xff1a;float定位&#xff1a;position 定位&#xff1a;手动…

MySQL —— 数据类型

目录 一、数据类型的分类 二、数值类型 1. tinyint类型 2. bit类型 3. float类型 4. decimal类型 三、字符串类型 1. char类型 2. varchar类型 3. char和varchar的比较 四、时间日期类型 五、enum和set类型 一、数据类型的分类 分类数据类型说明数值类型BIT(M)位…

《深入浅出计算机组成原理》学习笔记 Day11

浮点数1. 浮点数的二进制转化2. 浮点数的加法和精度损失参考1. 浮点数的二进制转化 以 9.1109.1_{10}9.110​ 为例。910100129_{10} 1001_2910​10012​&#xff0c;再把小数位转换为二进制。以 0.100120.1001_20.10012​ 为例&#xff1a; 0.1001212−102−202−312−40.562…

吊打大厂:内核级安卓系统优化软件 | 雪豹速清app官网下载

雪豹速清app是当前非常热门的一款安卓系统垃圾清理优化工具&#xff0c;具有雪豹文件管理器、大文件查找、冗余文件/重复文件清理、安卓内核级垃圾清理、QQ微信专清、文件秒搜、M3U8视频合并、微信语音导出、伪装音视频查找、安装包提取等诸多特色实用功能&#xff0c;雪豹速清…

LCR TC1 测试仪

用于检测NPN PNP 晶体管 电阻 电容二极管 三极管 NMOS PMOS IGBT JFET 可控硅 红外波形 &#xff0c;具有自校准功能。我手里的是TC-V2.12k 版本红外检测方法 &#xff1a;红外遥控器对准接收口&#xff0c;然后按下发送 即可检测 检测出 usercode 和datacode产品参数1.8寸屏幕…

Python内置包Tkinter的重要控件(上)

学习了这么久的Tkinter&#xff0c;基本上把Tkinter的重要控件都学了一遍&#xff0c;本文主要对其所有重要控件以及重要函数做一个总结&#xff0c;加深对Tkinter的理解与应用。 目录 前言 控件 1. Label 2. Button 3. Entry 4. Text 5. Menu 总结 前言 包括但不限…

MyBatis(一)MyBatis概述

一、什么是框架 ● 在文献中看到的framework被翻译为框架 ● java常用的框架&#xff1a; SSM三大框架&#xff1a;SpingSpringMVCMyBatisSpringBootSpringCloud● 框架其实就是对通用代码的封装&#xff0c;提前写好了一堆接口和类&#xff0c;我们可以在做项目的时候直接引…

Golang学习日志 ━━ gin-vue-admin前后端实现tinymce编辑器的上传功能

gin-vue-admin是一套国人用golang开发的后台管理系统&#xff0c;总体还是值得推荐的&#xff0c;其前端使用element-ui&#xff0c;后端使用gin框架。 官网&#xff1a;https://www.gin-vue-admin.com/ 本文主要描述tinymce的使用&#xff0c;很简单&#xff0c;基本流程如下&…

【Git】Git 的基本使用

Git的简介 Git是一个版本管理控制系统(缩写VCS)&#xff0c;是一个工具&#xff0c;github或者gitee是git命令行工具的网站化。它可以在任何时间点&#xff0c;将文档的状态作为更新记录保存起来&#xff0c;也可以在任何时间点&#xff0c;将更新记录恢复回来。 git的诞生历…

Java 方法

文章目录1. 方法的定义和调用2. 带参方法的定义和调用3. 带返回值方法的定义和调用4. 方法的注意事项5. 方法重载6. 方法的参数传递1. 方法的定义和调用 方法是将具有独立功能的代码块组织成为一个整体&#xff0c;使其具有特殊功能的代码集。 注意&#xff1a; ① 方法必须先…

Linux设置yum命令镜像

本文所有内容基于centos7&#xff0c;理论上对于所有的centos版本都是有效的 使用虚拟机安装linux一般都是默认最小安装&#xff0c;安装完linux之后会发现很多的命令是无法使用的&#xff0c;需要使用yum install进行安装&#xff08;很多博客写使用wget下载yum源&#xff0c…

(Java高级教程)第四章必备前端基础知识-第三节1:JavaScript简介和基础语法

文章目录一&#xff1a;JavaScript简介&#xff08;1&#xff09;JavaScript概述&#xff08;2&#xff09;JavaScript特点&#xff08;3&#xff09;JavaScript运行过程&#xff08;4&#xff09;JavaScript组成&#xff08;5&#xff09;JavaScript的引入方式和基本使用&…