Golang实战ES
- 一、ES的安装
- 下载elasticSearch7.7.0
- docker-compose启动elasticSearch7.7.0
- 安装中文分词器IK
- 注意事项
- 二、ES的简单的应用
- 查询
- 简单查询
- 复合条件查询
- 三、ES的在go中实战项目运用
- 安装
- 连接
- 查询索引
- 添加
- 查询
- 更新
- 删除
- 返回搜索词高亮处理
一、ES的安装
下载elasticSearch7.7.0
docker pull elasticsearch:7.7.0 //下拉镜像
docker images //查看镜像
//创建所需文件
mkdir -p /mydata/elasticsearch/config
mkdir -p /mydata/elasticsearch/data
echo "http.host: 0.0.0.0">>/mydata/elasticsearch/config/elasticsearch.yml
//文件夹赋权
chmod -R 777 elasticsearch/
//命令启动
docker run --name elasticsearch -p 9200:9200 \
-p 9300:9300 \
-e "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms64m -Xmx128m" \
-v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \
-v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
-d elasticsearch:7.7.0
//参数说明
--name elasticsearch:将容器命名为 elasticsearch
-p 9200:9200:将容器的9200端口映射到宿主机9200端口
-p 9300:9300:将容器的9300端口映射到宿主机9300端口,目的是集群互相通信
-e "discovery.type=single-node":单例模式
-e ES_JAVA_OPTS="-Xms64m -Xmx128m":配置内存大小
-v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:将配置文件挂载到宿主机
-v /mydata/elasticsearch/data:/usr/share/elasticsearch/data:将数据文件夹挂载到宿主机
-v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins:将插件目录挂载到宿主机(需重启)
-d elasticsearch:7.7.0:后台运行容器,并返回容器ID
docker-compose启动elasticSearch7.7.0
//docker-compose启动
version: '2'
services:
elasticsearch:
container_name: elasticsearch
image: elasticsearch:7.7.0
ports:
- "9200:9200"
volumes:
- /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
- /mydata/elasticsearch/data:/usr/share/elasticsearch/data
- /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins
environment:
- "ES_JAVA_OPTS=-Xms64m -Xmx128m"
- "discovery.type=single-node"
- "COMPOSE_PROJECT_NAME=elasticsearch-server"
restart: always
//查看容器
docker ps -a
//验证是否成功
curl http://192.168.0.50:9200/
//返回信息
{
"name" : "550eca5cf3b2",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "1mP9IJU3TUy_C2DZMfKGBg",
"version" : {
"number" : "7.7.0",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "81a1e9eda8e6183f5237786246f6dced26a10eaf",
"build_date" : "2020-05-12T02:01:37.602180Z",
"build_snapshot" : false,
"lucene_version" : "8.5.1",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
//Docker启动容器自启
docker update elasticsearch --restart=always
安装中文分词器IK
1.在线安装
//进入容器
docker exec -it elasticsearch /bin/bash
//在线下载并安装
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.5.4/elasticsearch-analysis-ik-6.5.4.zip
//进入plugins可以看到IK分词器已经安装成功
目录中有analysis-ik安装成功
2.离线安装
//将IK分词器上传到/tmp目录中elasticsearch-analysis-ik-6.5.4.zip
//将压缩包移动到容器里面
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
//将文件压缩包移动到ik中
mv /usr/share/elasticsearch/plugins/elasticsearch-analysis-ik-6.5.4.zip /usr/share/elasticsearch/plugins/ik
//进入目录
cd /usr/share/elasticsearch/plugins/ik
//解压
unzip elasticsearch-analysis-ik-6.5.4.zip
//删除压缩包
rm -rf elasticsearch-analysis-ik-6.5.4.zip
//退出并重启镜像
exit
docker restart elasticsearch
注意事项
*** 注意 安装中文分词器版本一定要和ES的版本号对应,不然会报错。
报错信息如下:
Exception in thread "main" java.lang.IllegalArgumentException: Plugin [analysis-ik] was built for Elasticsearch version 7.0.0 but version 7.7.0 is running
at org.elasticsearch.plugins.PluginsService.verifyCompatibility(PluginsService.java:346)
at org.elasticsearch.plugins.InstallPluginCommand.loadPluginInfo(InstallPluginCommand.java:814)
at org.elasticsearch.plugins.InstallPluginCommand.installPlugin(InstallPluginCommand.java:869)
at org.elasticsearch.plugins.InstallPluginCommand.execute(InstallPluginCommand.java:254)
at org.elasticsearch.plugins.InstallPluginCommand.execute(InstallPluginCommand.java:224)
at org.elasticsearch.cli.EnvironmentAwareCommand.execute(EnvironmentAwareCommand.java:86)
at org.elasticsearch.cli.Command.mainWithoutErrorHandling(Command.java:127)
at org.elasticsearch.cli.MultiCommand.execute(MultiCommand.java:91)
at org.elasticsearch.cli.Command.mainWithoutErrorHandling(Command.java:127)
at org.elasticsearch.cli.Command.main(Command.java:90)
at org.elasticsearch.plugins.PluginCli.main(PluginCli.java:47)
查看对应IK版本号:https://github.com/medcl/elasticsearch-analysis-ik/releases
安装完成重启ES
docker restart elasticsearch
IK分词使用
请求地址POST:http://127.0.0.1/_analyze?pretty
{
"analyzer": "ik_smart",
"text": "中华人民共和国国歌"
}
//返回内容
{
"tokens": [
{
"token": "中华人民共和国",
"start_offset": 0,
"end_offset": 7,
"type": "CN_WORD",
"position": 0
},
{
"token": "国歌",
"start_offset": 7,
"end_offset": 9,
"type": "CN_WORD",
"position": 1
}
]
}
ik_max_word:最细粒度的拆分
ik_smart: 最粗粒度的拆分
二、ES的简单的应用
查询
简单查询
Query Context 处理判断文档是否满足查询条件以外,ES还会计算一个_score 来标识匹配程度,判断目标文档与查询条件匹配的有多好。 常用查询 针对文本类型数据 字段级别的查询 针对结构化数据,如数字,日期。
Post请求 127.0.0.1/book/_search
//模糊查询
{
"query":{
"match":{
"author":"瓦力"
}
}
}
//准确查询
{
"query":{
"match_parase":{
"author":"瓦力"
}
}
}
//多字段的匹配查询(查询autor和title包含瓦力的)
{
"query":{
"multi_match":{
"query":"瓦力",
"fields":["author", "title"]
}
}
}
//查询瓦力和很好或则是python
{
"query":{
"query_string":{
"query":"(瓦力 AND 很好)OR python",
}
}
}
//查询瓦力和很好或则是python(在author和title字段中)
{
"query":{
"query_string":{
"query":"(瓦力 AND 很好)OR python",
"fields":["author", "title"]
}
}
}
//字段级别的查询,查询字数等于1000的图书
{
"query":{
"term":{
"word_count": 1000
}
}
}
//字段级别的查询,查询字数在1000-2000的图书有哪些,
//now表示现在时间,gte表示大于等于,gt表示大于
{
"query":{
"range":{
"word_count":{
"gte":1000,
"lte":2000
}
}
}
}
Filter Context 子条件查询 在查询过程中,只判断该文档是否满足条件,只有Yes或No 进行数据过滤,会加到缓存中,比query要快
//查询字数在一千字的书籍
{
"query": {
"bool": {
"filter": {
"term": {
"word_count": 1000
}
}
}
}
}
复合条件查询
//POST 127.0.0.1/_search
//全文查询,但是给出的评分不是一样的
{
"query": {
"match": {
"title": "ElasticSeach"
}
}
}
//固定评分查询,结果评分全部是1,不支持match
{
"query": {
"constant_score": {
"filter": {
"match": {
"title": "ElasticSearch"
}
},
"boost": 2 //指定分数查询,
}
}
}
//must必须查询条件
{
"query": {
bool": {
"should": [
{
"match": {
"author": "瓦力"
}
},
{
"match":{
"title": "ElasticSearch"
}
}
],
"filter": [
{
"term":{
"word_count": 1000
}
}
]
}
}
}
}
//must_not.不满足条件,筛选处作者没有瓦力的条件
{
"query": {
"must_not": {
"term": {
"author": "瓦力"
}
}
}
}
三、ES的在go中实战项目运用
安装
1.根据版本安装依赖(注意go mod 安装和直接安装方法不一样,下面是go mod 安装)
"github.com/olivere/elastic/v7"
连接
//连接客户端
client, err := elastic.NewClient(elastic.SetURL(esUrl), elastic.SetSniff(false))
if err != nil {
// Handle error
fmt.Println("出错了")
panic(err)
}
// Ping the Elasticsearch server to get e.g. the version number
// ping通服务端,并获得服务端的es版本,本实例的es版本为version 7.6.1
info, code, err := client.Ping(esUrl).Do(ctx)
if err != nil {
// Handle error
panic(err)
}
fmt.Println("开始打印版本号")
fmt.Printf("Elasticsearch returned with code>: %d and version %s\n", code, info.Version.Number)
// 获取版本号的直接API
esVersion, err := client.ElasticsearchVersion(esUrl)
if err != nil {
panic(err)
}
fmt.Printf("es的版本为%s\n", esVersion)
查询索引
//连接客户端
client, err := elastic.NewClient(elastic.SetURL(esUrl), elastic.SetSniff(false))
if err != nil {
// Handle error
fmt.Println("出错了")
panic(err)
}
// Ping the Elasticsearch server to get e.g. the version number
// ping通服务端,并获得服务端的es版本,本实例的es版本为version 7.6.1
info, code, err := client.Ping(esUrl).Do(ctx)
if err != nil {
// Handle error
panic(err)
}
fmt.Println("开始打印版本号")
fmt.Printf("Elasticsearch returned with code>: %d and version %s\n", code, info.Version.Number)
// 获取版本号的直接API
esVersion, err := client.ElasticsearchVersion(esUrl)
if err != nil {
panic(err)
}
fmt.Printf("es的版本为%s\n", esVersion)
添加
//连接客户端
client, err := elastic.NewClient(elastic.SetURL(esUrl), elastic.SetSniff(false))
if err != nil {
// Handle error
fmt.Println("出错了")
panic(err)
}
// Ping the Elasticsearch server to get e.g. the version number
// ping通服务端,并获得服务端的es版本,本实例的es版本为version 7.6.1
info, code, err := client.Ping(esUrl).Do(ctx)
if err != nil {
// Handle error
panic(err)
}
fmt.Println("开始打印版本号")
fmt.Printf("Elasticsearch returned with code>: %d and version %s\n", code, info.Version.Number)
// 获取版本号的直接API
esVersion, err := client.ElasticsearchVersion(esUrl)
if err != nil {
panic(err)
}
fmt.Printf("es的版本为%s\n", esVersion)
查询
5.查询
get1, err := client.Get().Index("user").Id("1").Do(ctx)
if err != nil{
panic(err)
}
if get1.Found{
fmt.Printf("Got document %s in version %d from index %s, type %s\n", get1.Id, get1.Version, get1.Index, get1.Type)
}
//将保存的内容保存到磁盘
_, err = client.Flush().Index("user").Do(ctx)
if err != nil {
panic(err)
}
// 按"term"搜索Search with a term query
termQuery := elastic.NewTermQuery("name", "mike")
searchResult, err := client.Search().
Index("user"). // 搜索的索引"user"
Query(termQuery). // specify the query
Sort("age", true). //按字段"age"排序,升序排列
From(0).Size(10). // 分页,单页显示10条
Pretty(true). // pretty print request and response JSON以json的形式返回信息
Do(ctx) // 执行
if err != nil {
// Handle error
panic(err)
}
fmt.Printf("Query took %d milliseconds\n", searchResult.TookInMillis)// 按"term"搜索Search with a term query
termQuery := elastic.NewTermQuery("name", "mike")
searchResult, err := client.Search().
Index("user"). // 搜索的索引"user"
Query(termQuery). // specify the query
Sort("age", true). //按字段"age"排序,升序排列
From(0).Size(10). // 分页,单页显示10条
Pretty(true). // pretty print request and response JSON以json的形式返回信息
Do(ctx) // 执行
if err != nil {
// Handle error
panic(err)
}
fmt.Printf("Query took %d milliseconds\n", searchResult.TookInMillis)
var user User
//Each是一个简便函数,此函数忽略了错误输出
for _, item1 := range searchResult.Each(reflect.TypeOf(user)) {
if u, ok := item1.(User); ok {
fmt.Printf("Person by %s,age:%d,married:%t,Sex:%s\n", u.Name, u.Age, u.Married,u.Sex) //Person by bob,age:23,married:false,Sex:male
}
// 搜索文档方法2
// 使用hits,获得更详细的输出结果
if searchResult.Hits.TotalHits.Value >0{
fmt.Printf("找到的数据总数是 %d \n", searchResult.Hits.TotalHits.Value)
for _,hits := range searchResult.Hits.Hits{
u :=User{}
err := json.Unmarshal([]byte(hits.Source), &u)
if err != nil{
fmt.Println("反序列化失败",err)
}
fmt.Printf("User by %s,age:%d,married:%t,Sex:%s\n", u.Name, u.Age, u.Married,u.Sex)
}
}else {
fmt.Println("没有搜到用户")
}
更新
// 更新文档 update
update, err := client.Update().Index("user").Id("1").
Script(elastic.NewScriptInline("ctx._source.age += params.num").Lang("painless").Param("num", 1)).
//Upsert(map[string]interface{}{"created": "2020-06-17"}). // 插入未初始化的字段value
Do(ctx)
if err != nil {
// Handle error
panic(err)
}
fmt.Printf("New version of user %q is now %d\n", update.Id, update.Version)
// 更新方法2
update,err := client.Update().Index("user").Id("1").
Script(elastic.NewScriptInline("ctx._source.created=params.date").Lang("painless").Param("date","2020-06-17")).
Do(ctx)
termQuery := elastic.NewTermQuery("name", "bob")
update,err = client.UpdateByQuery("user").Query(termQuery).
Script(elastic.NewScriptInline("ctx._source.age += params.num").Lang("painless").Param("num", 1)).
Do(ctx)
if err != nil{
panic(err)
}
fmt.Printf("New version of user %q is now %d\n", update.Id, update.Version)
fmt.Println(update)
删除
//删除文档
termQuery := elastic.NewTermQuery("name", "mike")
_, err = client.DeleteByQuery().Index("user"). // search in index "user"
Query(termQuery). // specify the query
Do(ctx)
if err != nil {
// Handle error
panic(err)
}
返回搜索词高亮处理
func QueryHeight(search dto.SearchActileDto,client *elastic.Client) (hightmap []bo.SearchActileBo,err error){
var data []bo.SearchActileBo
textFild:=elastic.NewHighlighterField("content")
//idFild:=elastic.NewHighlighterField("id")
//fild.PreTags("<em>")
//fild.PostTags("</em>")
titleFild:=elastic.NewHighlighterField("title")
titleFild.FragmentSize(350)
higthFild :=elastic.NewHighlight()
higthFild.Fields(titleFild)
higthFild.Fields(textFild)
//higthFild.Fields(idFild)
//两个里面必须有
//query :=elastic.NewBoolQuery().Must(elastic.NewMatchPhraseQuery("title","css"),elastic.NewMatchPhraseQuery("text","css"))
query :=elastic.NewBoolQuery().Should(elastic.NewMatchPhraseQuery("title",search.SearchWord),elastic.NewMatchPhraseQuery("content",search.SearchWord))
res, err := client.Search("article").Query(query).Highlight(higthFild).Size(int(search.Size)).From(int((search.Current - 1) * search.Size)).Do(context.Background())
if err != nil {
return nil,err
}
//fmt.Println(res.Hits.Hits)
for _, hit := range res.Hits.Hits {
aa :=hit.Highlight
var search bo.SearchActileBo
search.ContentId = hit.Id
var qq dto.Article
json.Unmarshal(hit.Source,&qq)
search.CreatTime = fmt.Sprintf("%v",qq.CreateTime)
search.CreateID = qq.CreateBy
if aa["title"] == nil{
search.Title=qq.Title
}else{
search.Title=aa["title"][0]
}
if aa["content"] == nil{
search.Content=qq.Content
}else{
search.Content = aa["content"][0]
}
data = append(data, search)
}
return data,nil
}