搜索
term 搜索
完全匹配,也就是精确查询,搜索前不会再对搜索词进行分词拆解,此文讲的很详细。
GET /megacorp/employee/_search { "query" : { "term" : { "about" : "rock climbing" } } }
match 搜索
与 term 搜索不同,会先将搜索词拆分,拆完后,再去匹配,此文讲的很详细。
Elasticsearch 默认按照相关性得分排序,即每个文档跟查询的匹配程度。也就是说你搜索”rock climbing”的话,只有”rock”的也可能被搜出来,只是相关性得分会很低,会排在后面点。例子:
GET /megacorp/employee/_search { "query" : { "match" : { "about" : "rock climbing" } } }
返回结果有两条,第一条:”about”:”I love to go rock climbing“,第二条:”about”:”I like to collect rock albums“。
短语搜索
找出一个属性中的独立单词是没有问题的,但有时候想要精确匹配一系列单词或者短语 。 比如, 我们想执行这样一个查询,仅匹配同时包含“rock” 和 “climbing” ,并且 二者以短语 “rock climbing” 的形式紧挨着的雇员记录。为此对 match 查询稍作调整,使用一个叫做 match_phrase 的查询:
GET /megacorp/employee/_search { "query" : { "match_phrase" : { "about" : "rock climbing" } } }
毫无悬念,返回结果仅有 John Smith 的文档。
通配符与正则表达式查询
GET /.ds-logs-generic-device_raw_log-2023.07.12-000001/_search { "query" : { "wildcard" : { "message" : "*hello*" } } }
分析
Elasticsearch 有一个功能叫聚合(aggregations),允许我们基于数据生成一些精细的分析结果。聚合与 SQL 中的 GROUP BY 类似但更强大。这里有个复杂案例:ElasticSearch 嵌套分桶的过滤与排序
histogram 统计(按时间)
histogram 统计能够对字段取值按间隔统计建立直方图(针对数值型和日期型字段),这里以日期型字段 @timestamp 为例讲解:
GET /logs-generic-device_raw_log/_search { "size":0, "aggs": { "按年月日统计,再按 host 字段统计": { "date_histogram": { "field": "@timestamp", "fixed_interval": "1d", "format": "yyyy-MM-dd" }, "aggregations": { "hostAgg": { "terms": { "field": "host", "size": 10, "min_doc_count": 1, "shard_min_doc_count": 0, "show_term_doc_count_error": false } } } } } }
返回值:
{ "aggregations" : { "按年月日统计,再按 host 字段统计" : { "buckets" : [ { "key_as_string" : "2023-04-03", "key" : 1680480000000, "doc_count" : 272, "hostAgg" : { "doc_count_error_upper_bound" : 0, "sum_other_doc_count" : 0, "buckets" : [ { "key" : "192.168.1.254", "doc_count" : 268 }, { "key" : "192.168.2.154", "doc_count" : 4 } ] } } ] } } }
参考:elasticsearch之十九springboot测试高级搜索聚合
(5)分析与 histogram 统计(按时间)
下面的 java 代码不仅包含日期型 histogram 统计,还包含嵌套 FiltersAggregationBuilder 过滤分组:
public ChartsDataset analyseRawData(String cycleTime, List<String> groupNames, ChartsTypeEnum type, String deviceName) { // 1. 创建 queryBuilder BoolQueryBuilder myquery = new BoolQueryBuilder(); if (groupNames.size() > 0) { BoolQueryBuilder messageQuery = new BoolQueryBuilder(); for (String groupName : groupNames) { messageQuery.should(QueryBuilders.matchQuery("message", groupName)); } myquery.must(messageQuery); } if (StringUtils.isNotBlank(deviceName)) { String messageQuery = "*" + deviceName + "*"; WildcardQueryBuilder wildcardQueryBuilder = QueryBuilders .wildcardQuery("message", messageQuery) .caseInsensitive(true); myquery.must(wildcardQueryBuilder); } DateHistogramInterval interval = null; String dateFormat = null; switch (cycleTime) { case "day": interval = DateHistogramInterval.DAY; dateFormat = "yyyy-MM-dd"; break; case "week": interval = DateHistogramInterval.WEEK; dateFormat = "yyyy-MM-dd"; break; case "month": interval = DateHistogramInterval.MONTH; dateFormat = "yyyy-MM"; break; } // 1. 创建 FiltersAggregationBuilder FiltersAggregator.KeyedFilter[] keyedFilters = new FiltersAggregator.KeyedFilter[groupNames.size()]; for (int i = 0; i < groupNames.size(); i++) { String groupName = groupNames.get(i); keyedFilters[i] = new FiltersAggregator.KeyedFilter(groupName, QueryBuilders.termQuery("message", groupName)); } FiltersAggregationBuilder filterAgg = AggregationBuilders .filters("subAgg", keyedFilters) .otherBucket(false) .otherBucketKey("other") // 使用 message 字段会报错,此字段不支持聚合的,是 text 类型。 .subAggregation(AggregationBuilders.count("num").field("_id")); // 2. 创建 date_histogram AggregationBuilder DateHistogramAggregationBuilder dateHistogramAggBuilder = AggregationBuilders.dateHistogram("myHistogram")//自定义名称 .calendarInterval(interval) //.fixedInterval(interval) //设置间隔 .minDocCount(0) //返回空桶 .field("@timestamp") .format(dateFormat) //.offset("+0h") //时区区间偏移值 //.extendedBounds(new LongBounds(time.get(0), time.get(1)))//指定时间字段 .subAggregation(filterAgg); // 3. 创建 NativeSearchQuery 进行查询 NativeSearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(myquery) .addAggregation(dateHistogramAggBuilder) .withMaxResults(0) .build(); SearchHits<DeviceRawLog> searchHits = esTemplate.search(searchQuery, DeviceRawLog.class); // 4. 获取结果 ChartsDataset dataset = new ChartsDataset(); dataset.getDimensions().add("name"); ParsedDateHistogram dateHistogram = searchHits.getAggregations().get("myHistogram"); for (Histogram.Bucket agg1Bucket : dateHistogram.getBuckets()) { String dateKey = agg1Bucket.getKeyAsString(); long dateCount = agg1Bucket.getDocCount(); List<Object> arr = new ArrayList<>(); arr.add(dateKey); if (type.equals(ChartsTypeEnum.PIE)) { dataset.getDimensions().add("value"); arr.add(dateCount); } if (type.equals(ChartsTypeEnum.BAR)) { ParsedFilters parsedFilters = agg1Bucket.getAggregations().get("subAgg"); for (Filters.Bucket bucket : parsedFilters.getBuckets()) { String agg2Key = bucket.getKeyAsString(); long agg2Count = bucket.getDocCount(); dataset.getDimensions().add(agg2Key); arr.add(agg2Count); ChartsBarSeries barSeries = new ChartsBarSeries(agg2Key, new ChartsBarEncode("name", agg2Key)); dataset.getBarSeries().add(barSeries); } } dataset.getSource().add(arr); } return dataset; }
分词器
analyzer:插入文档时,将text类型的字段做分词然后插入倒排索引。
search_analyzer:查询时,先对要查询的text类型的输入做分词,再去倒排索引中搜索。
如果想要让’索引’和’查询’时使用不同的分词器也是能支持的,只需要在字段上加search_analyzer参数,索引时,只会去看字段有没有定义analyzer,有定义的话就用定义的,没定义就用es预设的。
查询时,会先去看字段有没有定义search_analyzer,如果没有定义,就去看有没有analyzer,再没有定义,才会去使用es预设的。
数据流 – Data Stream
数据流可以跨多个索引存储,需要有个索引模板(index template),模板中包含映射(mappings) 和 索引设置(settings)。基于滚动索引,可按时间间隔、文档数、分片大小进行滚动。
数据流相对实体索引,有点“抽象层“的概念,其核心数据还是存储在.ds前缀的后备索引中。
数据流需要指定一个匹配的索引模板。在大多数情况下,可以使用一个或多个组件模板(component template)来组成此索引模板。通常使用单独的组件模板进行映射和索引设置。这样可以重用多个索引模板中的组件模板。
在使用数据流时,当前的数据流必须匹配一个索引模板,用于给数据流创建索引。数据流当前索引是无法被删除的,要删除必须滚动数据流,以便创建新的写入索引。然后才可使用删除索引 API 删除以前的写入索引,参考。不过可以直接删除数据流,此时数据流当前索引也被一起删除了。
Change mappings and settings for a data stream
此外经测,索引模板 mapping 字段发生变化后(比如修改分词器),数据流中数据会在 Kibina中显示不出,且新加入的数据也显示不出。删除数据流,重新加入新数据才可以展示出数据!
索引模板发生变化后,数据流的当前索引是不会变的,新创建的索引才会用变化后的模板来创建,要立即生效最快的办法就是删除数据流,此时数据流下的当前索引会一起删除!
如果新数据流或索引与多个索引模板匹配,则使用优先级最高的索引模板。
数据流特点:
- data stream 是时序索引的上层抽象。
- data stream 是模板、索引、settings、mappings、ilm policy等综合体的概念。
- data stream 相当于抛头露面的带头大哥,离不开看似隐身、默默无闻、实际埋头苦干的后备索引的支撑。
- data stream 不适合频繁删除、更新的业务场景,更适合仅追加时序数据场景。
- 只能基于 data stream 写入数据,不能基于后备索引写入数据。
- data stream 不支持单条删除或单条更新数据,只支持:update_by_query 以及 delete_by_query。
Kibana
使用Kibana 可对Elasticsearch 索引中的数据进行搜索、查看、交互操作。
(1)使用 docker run 启动
docker pull kibana:7.13.4 docker run --name kib --rm -p 5601:5601 kibana:7.13.4
(2)使用 Swarm 配置启动( mykibana.yaml)
version: '3.2' services: mykibana: image: kibana:7.13.4 ports: - "5601:5601" environment: ELASTICSEARCH_HOSTS: '["http://elasticsearch:9200"]' depends_on: - elasticsearch networks: - mynet deploy: placement: constraints: - node.labels.storm == true networks: mynet: external: name: policy_mynet
容器起来后需要先创建索引模式:




集群状态
集群黄色状态解读:

bootstrap checks failed 错误解决
(1)max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]
解决办法:
第一步:切换到root用户,修改 /etc/security/limits.conf 添加如下内容:
* soft nofile 65536 * hard nofile 131072 * soft nproc 4096 * hard nproc 4096
第二步:切换到root用户,修改 /etc/security/limits.d/20-nproc.conf 添加如下内容:
* soft nproc 1024 #修改为 * soft nproc 4096
(2)max number of threads [1024] for user [admin] is too low, increase to at least [4096]
解决办法和上面(1)一样。
(3) max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
解决办法:
切换到root用户,修改 /etc/sysctl.conf ,添加:vm.max_map_count=655360,
并执行命令:sudo sysctl -p
。
注意:如果是 docker-compose 部署,改的是宿主主机。这个设置在安装前就应该先设置。
(4)system call filters failed to install; check the logs and fix your configuration or disable system call filters at your own risk
解决办法:
修改 elasticsearch.yml,添加:
bootstrap.memory_lock: false bootstrap.system_call_filter: false