go语言实战es,高亮全文检索关键词等!

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("")
	//fild.PostTags("")
	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
}
欢迎私信我交流更多ES用法

你可能感兴趣的:(Golang,golang,全文检索,elasticsearch)