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表示必须一致才会高亮
      }
    }
  }
}

 

posted @ 2024-03-07 11:43  凌碎瞳缘  阅读(23)  评论(0编辑  收藏  举报