ES - 基于Golang的简单使用ElasticSearch

AI 摘要: 修复安装问题中的exit with 137和exited with code 78错误

1. 安装

1.1. 安装问题

1.1.1. 资源相关问题

  1. exit with 137: 内存配置问题ES_JAVA_OPTS=-Xms1024m -Xmx1024m
  2. exited with code 78: 文件资源问题

1.1.2. es 的 data 存储目录可能混用了

我之前先部署的集群,出现了上述13778问题,转回到单节点上来,一直退出。修复方式:直接移除了 Docker 之前绑定卷,重新运行服务一切正常!

1
2
es01_1  | {"type": "server", "timestamp": "2019-11-14T09:07:31,790Z", "level": "INFO", "component": "o.e.x.m.p.NativeController", "cluster.name": "docker-cluster", "node.name": "aeb81e220110", "message": "Native controller process has stopped - no new native processes can be started" }
elastic_es01_1 exited with code 1

1.1.3. Docker 安装

见文末的docker-composer.yml配置文件

1.2. 插件安装1

对于 Elasticsearch 5.x、6.x 和 7.x plugins 安装方式有差异,插件必须安装在群集中的每个节点上,并且每个节点必须在安装后重新启动。

1
2
3
4
5
6
// file
bin/elasticsearch-plugin install file:///path/to/plugin.zip
// http
bin/elasticsearch-plugin install http://some.domain/path/to/plugin.zip
// ssl ca认证
ES_JAVA_OPTS="-Djavax.net.ssl.trustStore=/path/to/trustStore.jks" bin/elasticsearch-plugin install https://host/plugin.zip

1.2.1. elasticsearch-head

推荐直接使用 chrome 插件,十分方便:elasticsearch-head chrome 插件

2. ES 使用

2.1. Golang 客户端库

Go 客户端库:https://github.com/olivere/elastic

2.2. Mapping2

  1. 6.x版本移除了索引_type,以前类别 ES 索引为 Mysql 索引,type为表,但数据库的表直接是隔离的,ES 从索引性能考虑除去了在索引中的mapping types
    • 每个文档类型创建一个索引
    • 自定义type选项

2.3. 分析器/分词器3

分析器一或多个字符过滤器+一个分词器(必须要有)一或多个分词过滤器三个模块组成,默认 ES 使用Standard Tokenizer标准的分词器,

1
2
3
4
5
6
// 测试分词器
POST /pinlist/_analyze
{
  "analyzer": "standard",
  "text": "在线教育上市公司 跟谁学 中台 诚招 资深Golang工程师,有兴趣可联系"
}

2.3.1. IK 分词器集成

  • 测试 ik 分词,https://github.com/medcl/elasticsearch-analysis-ik/releases
1
2
3
4
5
6
// v7.4.2版本安装,可能权限问题,需要手动确认下
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.4.2/elasticsearch-analysis-ik-7.4.2.zip

// 安装完成后
[root@ac59438dbec4 elasticsearch]# ./bin/elasticsearch-plugin list
analysis-ik

2.3.2. IK 分词器配置

  • IK 可以支持自定义设定词库扩展词典停止词,同时可以支持外部热更新这两类词;远程词文件基于 HTTP 响应,其 HTTP 头的Last-ModifiedEtag两个标签任意一个有变动即更新词库,内容基于\n换行符分割,同时需要保证是UTF-8编码的。
  • 配置放置在/usr/share/elasticsearch/config/analysis-ik/IKAnalyzer.cfg.xml,更多细节参考IK 分词热更新
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
[root@ac59438dbec4 elasticsearch]# cat config/analysis-ik/IKAnalyzer.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
    <comment>IK Analyzer 扩展配置</comment>
    <!--用户可以在这里配置自己的扩展字典 -->
    <entry key="ext_dict"></entry>
     <!--用户可以在这里配置自己的扩展停止词字典-->
    <entry key="ext_stopwords"></entry>
    <!--用户可以在这里配置远程扩展字典 -->
    <!-- <entry key="remote_ext_dict">words_location</entry> -->
    <!--用户可以在这里配置远程扩展停止词字典-->
    <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

2.3.3. ES 使用 IK 分词器查询

  • ik_max_word: 最细粒度的文本拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”,会穷尽各种可能的组合,适合Term Query术语查询
  • ik_smart: 最粗粒度的文本拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”,适合Phrase短语查询
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
GET /_analyze
{
  "tokenizer": "ik_max_word",
  "text": ["中华人民共和国国歌","美国留给伊拉克的是个烂摊子吗", "公安部:各地校车将享最高路权"]
}
GET /_analyze
{
  "tokenizer": "ik_smart",
  "text": ["中华人民共和国国歌","美国留给伊拉克的是个烂摊子吗", "公安部:各地校车将享最高路权"]
}

2.4. Query DSL

Query DSL简称为查询领域语言,提供了基于 JSON 的完整查询 DSL(特定于域的语言)来定义查询。将查询 DSL 视为查询的 AST(抽象语法树),它由两种子句组成:

  1. 叶子查询子句在特定字段中查找特定值,例如match,term或range查询,这些查询可以被他们自己使用。
  2. 复合查询子句组合其他叶查询或复合查询,并用于以逻辑方式组合多个查询(例如booldis_max查询),或更改其行为(例如constant_score查询)

2.4.1. 查询和过滤上下文区别

默认情况,ES 基于得分排序查询的结果,得分越高表示文档和查询内容越匹配,即_score得分字段;

  1. 查询query上下文,回答了这个文档与查询内容有多么的匹配的问题,通过_search API传递query参数
  2. 过滤filter上下文,回答了这个文档是否与查询内容匹配,比如某某日期是否在一个区间范围,某个状态是否为有效状态等,通过查询语句设定filter参数,诸如在bool查询中,指定must_notfilter参数

以下查询是一个bool组合查询,通过query指定bool查询中,有两个match查询,这个是用于指示结果与搜索条件有多匹配;还有两个filter指示结果应该排除状态以及日期不匹配的情况;

Tips: 在查询上下文中使用查询子句来确定会影响匹配文档得分的条件(即文档匹配程度),并在过滤器上下文中使用所有其他查询子句。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "must": [
        { "match": { "title":   "Search"        }},
        { "match": { "content": "Elasticsearch" }}
      ],
      "filter": [
        { "term":  { "status": "published" }},
        { "range": { "publish_date": { "gte": "2015-01-01" }}}
      ]
    }
  }
}
'

2.4.2. 查询

  1. 复合查询:
    • bool相关子句类型:mustfiltershouldmust_not;
  2. minimum_should_match参数:指定查询子句应该如何处理,比如子句条数、百分比等(用于调整查询结果的关联度)
  3. 全文查询,使用和索引期间相同的分析器
    • match: 执行全文查询的标准查询,包括模糊匹配和短语或接近查询
    • mutil_match: match查询的多字段版本,支持在多个字段中查询
    • common: 对不常见的单词给予更多的偏爱,即权重更高
    • query_string: 支持紧凑的 Lucene 查询字符串语法,允许您在单个查询字符串中指定AND|OR|NOT条件多字段搜索,仅限于专业用户(lucene 语法查询,比如title:(quick OR brown))
    • simple_query_string: 适用于直接向用户公开的 query_string 语法的更简单,更可靠的版本;
    • match_phrase: 类似于match查询,但用于匹配完全匹配的词组或单词接近匹配
    • match_phrase_prefix: 类似于match_phrase查询,但是对最后一个单词进行通配符搜索
    • match_bool_prefix: 分析查询输入,将其转换从多个term查询,同时对最后一个单词进行通配符搜索
  4. Term术语查询,查询不会分析搜索词,用于精确值查找文档
    • exists:返回包含字段的任何索引值的文档
    • fuzzy:返回包含与搜索词相似的词的文档,使用Levenshtein算法来衡量相似性或模糊性 。
    • ids: 根据文档 ID 返回文档。
    • prefix: 返回在提供的字段中包含特定前缀的文档。
    • range:范围查询,比如gt、gte、lt、lte,支持format
    • regexp:返回包含与正则表达式匹配的术语的文档。
    • term: 返回在提供的字段中包含确切术语的文档,可以使用 term 查询根据精确的值(例如价格,产品 ID 或用户名)查找文档,避免 term 对 text 字段使用查询,默认情况下,Elasticsearch 更改 text 字段的值作为 analysis 的一部分。这会使查找 text 字段值的精确匹配变得困难,要搜索 text 字段值,请改用 match 查询。
    • terms:返回在提供的字段中包含一个或多个确切术语的文档。

2.5. 搜索 APIs

Explain外,大多数搜索 API 都是支持多索引的,

搜索 APIs 部分涵盖了搜索语法、搜索模板、高亮、解析、校验等内容

2.5.1. 基于请求 Body 搜索 4

  • from/size
  • sort
  • highlight

2.5.2. 高亮搜索5

许多应用都倾向于在每个搜索结果中 高亮 部分文本片段,以便让用户知道为何该文档符合查询条件。

再次执行前面的查询,并增加一个新的highlight参数;当执行该查询时,返回结果与之前一样,与此同时结果中还多了一个叫做highlight的部分。这个部分包含了about属性匹配的文本片段,并以HTML标签 封装:

Tips: 如果将该number_of_fragments值设置为0,则不会产生任何片段(默认高亮 100 字符,5 个片段),而是返回该字段的全部内容,并且当然会突出显示该字段。

2.6. Docker Compose

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
version: "3.7"
services:
    kibana:
        image: kibana:7.4.2
        container_name: kibana
        environment:
            - ELASTICSEARCH_HOSTS=http://es01:9200
        volumes:
            - /private/var/lib/elastic/kibana/data:/usr/share/kibana/data
        ports:
            - 5601:5601
        # entrypoint: ["echo", "service was temporarily supspended!!"]
        networks:
            - elastic
    es01:
        image: elasticsearch:7.4.2
        environment:
            - node.name=es01
            - cluster.name=es-docker-cluster
            - network.host=_local_,_site_
            - network.publish_host=_local_
            - discovery.type=single-node
            - bootstrap.memory_lock=true
            - "ES_JAVA_OPTS=-Xms750m -Xmx750m"
        ulimits:
            memlock:
                soft: -1
                hard: -1
            nofile:
                soft: 65535
                hard: 65535
        volumes:
            - /private/var/lib/elastic/elasticsearch/data01:/usr/share/elasticsearch/data
            - /private/var/lib/elastic/elasticsearch/plugins:/usr/share/elasticsearch/plugins
        ports:
            - 9200:9200
            - 9300:9300
        networks:
            - elastic
networks:
  elastic:
    driver: bridge