elasticsearch——搜索引擎工具
部署ES和kibana
创建一个网络,到时候ES要和kibana(可视化工具)放同一个网络(也可以直接用docker-compose一键部署,不过有时不需要两个都开,所以逐一部署吧)
docker network create es-net
然后去DockerHub找文档,docker pull一下ES和kibana,或者网上找镜像包
单点部署ES
docker run -d \
--name es \
-e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \ #设置内存大小
-e "discovery.type=single-node" \ #设置单点部署
-v es-data:/usr/share/elasticsearch/data \ #设置数据卷
-v es-plugins:/usr/share/elasticsearch/plugins \
--privileged \ #授予容器特权
--network es-net \ #设置在docker的哪个网络
-p 9200:9200 \ #HTTP端口
-p 9300:9300 \ #容器互联端口
elasticsearch:7.12.1
部署kibana
docker run -d \
--name kibana \
-e ELASTICSEARCH_HOSTS=http://es:9200 \ #ES的HTTP端口地址
--network=es-net \ #与ES放入同一个网络
-p 5601:5601 \
kibana:7.12.1
配置ES字典
进入Dev tools,编写下列DSL来操作elasticsearch,我们会发现,默认分词器无法识别中文词语,所以我们选择安装IK分词器插件
POST /_analyze
{
"text":"超级霹雳霸王龙666",
"analyzer": "english"
}
查找一下ES数据卷的目录,将IK插件放入/usr/share/elasticsearch/plugins目录搭载的数据卷下,上述写的数据卷名应该是es-plugins
docker volume inspect 想查找的数据卷名
将IK文件放入/usr/share/elasticsearch/plugins的数据卷目录下后,重启ES
docker restart es #重启es容器
docker logs -f es #查看es日志
IK分词器包含两种模式
GET /_analyze
{
"analyzer": "ik_smart", #进行最基础的单词切分,不会细分,运行速度会快些
"text": "超级霹雳霸王龙666"
}
GET /_analyze
{
"analyzer": "ik_max_word", #将单词进行细分,能更精确的找到数据
"text": "超级霹雳霸王龙666"
}
我们还可以对分词器添加词语或剔除词语,进入IK文件夹下的config目录,当中会有个叫做IKAnalyzer.cfg.xml文件,对文件进行配置。(ext.dic和stopword.dic为当前目录下的文件)在ext.dic和stopword.dic文件中写入要扩展的词即可(别忘了重启ES)
操作索引库
创建索引库
PUT /lsty #索引库名称
{
"mappings": {
"properties": {
"id":{ #字段名
"type": "keyword" #id字段很特别,存入的是字符串,不是数字,所以我们用keyword(不可分割的字符型)
},
"info":{
"type":"text", #可分割的字符型
"analyzer": "ik_smart" #选用的分词器
},
"score":{
"type": "integer" #整数型
},
"email":{
"type": "keyword", #keyword为精确值字段,即为不可拆分
"index": false #是否创建索引,默认为true(创建索引)
},
"location":{
"type": "geo_point" #点坐标类型字段,还有一个几何坐标类型geo_shape
},
"name":{
"type": "object",
"properties": {
"firstName":{ #子字段
"type": "keyword"
},
"lastName":{
"type": "keyword"
}
}
},
"brand":{
"type": "keyword",
"copy_to": "all" #利用copy_to,将brand拷贝到all字段
},
"business":{
"type": "keyword",
"copy_to": "all" #利用copy_to,将business拷贝到all字段
},
"all":{
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
查询索引库
GET /lsty #索引库名
删除索引库
DELETE /lsty #索引库名
添加索引库字段(ES中,索引库是不允许修改的,只能添加字段)
PUT /lsty/_mapping/
{
"properties":{
"age":{
"type":"long"
}
}
}
数据操作
添加数据
这不止可以用来添加数据,其实也可以修改数据,但会将原先内容全部删除,换成新的内容
POST /lsty/_doc/1 #/lsty/_doc为固定格式,1是数据ID
{
"info": "超级无敌霹雳霸王龙666凌碎瞳缘",
"email": "2932105288@qq.com",
"name":{
"firstName":"云",
"lastName":"赵"
}
}
如果只想要修改某条内容,可以使用这种方式修改
POST /lsty/_update/1
{
"doc":{
"email":"3223412332@qq.com"
}
}
获取和删除数据
GET /lsty/_doc/1
DELETE /lsty/_doc/1
简单查询操作
查询索引库中所有数据
GET /lsty/_search
{
"query": {
"match_all": {}
}
}
查询all字段与“如家”有关的数据(此处all为包含了两个子字段的字段,和上述的match_all无关)
GET /lsty/_search
{
"query": {
"match": {
"all": "如家"
}
}
}
查找name,brand,business字段与“北京酒店”有关的数据(我们一般推荐上一个方法查找,尽量减少查询字段)
GET /lsty/_search
{
"query": {
"multi_match": {
"query": "北京酒店",
"fields": ["name","brand","business"]
}
}
}
精确查找city字段为“上海”的数据
GET /lsty/_search
{
"query": {
"term": {
"city": {
"value": "上海"
}
}
}
}
查找price为1000到2000区间的所有数据
GET /lsty/_search
{
"query": {
"range": {
"price": {
"gte": 1000,
"lte": 2000
}
}
}
}
查找30.20,120.5经纬度下,1.5km范围内的所有数据
GET /lsty/_search
{
"query": {
"geo_distance": {
"distance": "1.5km",
"location": "30.20,120.5"
}
}
}
复杂查询操作
修改原先的相关性权值,得到新的排序
GET /lsty/_search
{
"query": {
"function_score": {
"query": {
"match": {
"all": "外滩"
}
},
"functions": [
{
"filter": { #只有过滤出的数据才会进行重新计分
"term": {
"brand": "如家"
}
},
"weight": 10 #filter过滤出来的数据添加的权重.还有别的函数可以算分,例如field_value_factor,random_score,script_score
}
],
"boost_mode": "multiply" #选择用什么方法,将query的权值和functions的权值进行整合,得出最终权重(还有replace,sum,avg,max,min)
}
}
}
bool组合子查询
#must_not和filter的查询结果不参与查询算分。所以当某些条件不影响排名时,用这两条进行查询,可以增加效率
GET /lsty/_search
{
"query": {
"bool": {
"must": [ #每个子查询都必须匹配
{"term": {"city": "上海" }}
],
"should": [ #有一个子查询匹配即可
{"term": {"brand": "皇冠假日"}},
{"term": {"brand": "华美达"}}
],
"must_not": [ #每个子查询都不匹配
{"range": {"price": {"lte": 500}}}
],
"filter": [ #每个子查询都必须匹配
{"range": {"score": {"gte": 45}}}
]
}
}
}
ES默认是用相关度进行算分排序,但是我们也可以取消掉相关性算分,进行sort排序
#根据分数降序,分数一样根据价格升序
GET /lsty/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"score": "desc",
"price": "asc"
}
]
}
#对经纬度122.11,30周围的数据,进行距离升序排序
GET /lsty/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"_geo_distance": {
"location": {
"lat": 30,
"lon": 122.11
},
"unit": "km", #sort分值单位,1km=1分
"order": "asc"
}
}
]
}
ES默认只会返回Top10的数据,如果需要调整返回的数据,需要更改from和size的值,这和MySQL数据库limit的分页参数很像。
需要注意的是,ES一般会做集群部署,这种情况下,假如我要获取Top200到Top300的数据,并且有500台服务器部署了ES,那么一次查询的数据量总和就是200*300*500=3e7。
这是非常恐怖的,所以ES会限制我们的查询量为10000,在业务逻辑上我们也会限制一次性大量的查询。
但如果我就是需要如此大的查询,ES也给我们提供了after search的查询方式,这种查询方式每次会存储上一次查询后的最后一名数据,以此为基础,继续查找下一批Top的数据。但因此该方法不支持随机翻页或向上翻页
GET /lsty/_search
{
"query": {
"match_all": {}
},
"from": 10, #从索引为10的结果开始获取
"size": 20 #获取20条数据
, "sort": [
{
"price": "asc"
}
]
}
关键字高亮展示
GET /lsty/_search
{
"query": {
"match": {
"all": "如家"
}
},
"highlight": {
"fields": {
"name": {
"pre_tags": "<em>", #决定了搜索到的关键字,前后加什么标签,如果不写,默认就是<em></em>
"post_tags": "</em>",
"require_field_match": "false" #决定了搜索字段和高亮字段是否要一致,true表示必须一致才会高亮
}
}
}
}