精通ES+ES大数据查询常见的疑难杂症的解决与实现

news/2024/7/7 5:48:18 标签: 大数据, elasticsearch, java

目录

 什么是BoolQueryBuilder?

简单的复合查询

RestHighLevelClient中的matchQuery与matchPhraseQuery与termQuery的在实际使用中的不同

ES是否能在类型为text的字段的内部使用keyword,如果能这样做的含义是什么?

什么是ES多字段?

ES怎么实现聚合查询?

RestHighLevelClient的subAggregation是什么?干什么用的?

什么是RestHighLevelClient的滚动查询?如何实现?

ES构建简单搜索


 什么是BoolQueryBuilder?

BoolQueryBuilder是该客户端库中的一个查询构建器,用于构建布尔查询(bool query)。 布尔查询是一种复合查询,可以将多个查询条件组合在一起。

BoolQueryBuilder提供了几种方法来构建布尔查询:

1. must(QueryBuilders): 添加一个“必须匹配”(must)的查询条件。这意味着文档必须满足该查询条件才能被返回。 相当于sql中的and

2. mustNot(QueryBuilders): 添加一个“不能匹配”(must not)的查询条件。这意味着文档不能满足该查询条件才能被返回。相当于 is not 

3. should(QueryBuilders): 添加一个“应该匹配”(should)的查询条件。这意味着文档可以满足该查询条件,但不是必须的。 相当与or

4. filter(QueryBuilders): 添加一个“过滤”(filter)的查询条件。与must查询条件类似,但过滤查询不会计算相关性得分,通常用于对结果进行筛选。相当与select 的字段

简单的复合查询

java">BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
    .must(QueryBuilders.termQuery("field1", "value1"))
    .mustNot(QueryBuilders.termQuery("field2", "value2"))
    .should(QueryBuilders.termQuery("field3", "value3"))
    .filter(QueryBuilders.termQuery("field4", "value4"));

// 将boolQuery用于搜索请求
SearchRequest searchRequest = new SearchRequest("indexName");
searchRequest.source(new SearchSourceBuilder().query(boolQuery));

RestHighLevelClient中的matchQuery与matchPhraseQuery与termQuery的在实际使用中的不同

1. matchQuery:  
The matchQuery is a full-text query that analyzes the provided text and generates a query that performs a full-text search on the analyzed text. It is useful when you want to perform a search based on relevance. The matchQuery analyzes the text and generates a set of terms that are used for matching.

翻译:

1.匹配查询:
matchQuery是一个全文查询,用于分析所提供的文本,并生成一个对所分析的文本执行全文搜索的查询。当您想要根据相关性执行搜索时,它非常有用。matchQuery分析文本并生成一组用于匹配的术语。

2. matchPhraseQuery: 
The matchPhraseQuery is similar to the matchQuery, but it analyzes the text as a phrase rather than individual terms. It is useful when you want to search for an exact phrase in the text. The matchPhraseQuery considers the order of the terms and their proximity to each other. 

2.匹配短语查询:
matchPhraseQuery类似于matchQuery,但它将文本作为短语而不是单个术语进行分析。当你想在文本中搜索一个确切的短语时,它很有用。matchPhraseQuery考虑术语的顺序及其彼此之间的接近程度。

termQuery: The termQuery is a query that searches for exact terms in a field. It does not analyze the text and is suitable for searching on keyword fields or fields that are not analyzed. The termQuery matches documents that contain an exact term.

术语查询:
termQuery是一个在字段中搜索精确术语的查询。它不分析文本,适用于搜索关键字字段或未分析的字段。termQuery匹配包含确切术语的文档。

总结:

matchQuery和matchPhraseQuery用于全文搜索并考虑相关性,而termQuery用于精确的术语匹配,不对文本执行分析。您可以根据特定的搜索要求选择适当的查询类型。

ok,

所以简单的来说,

如果搜随机的话请使用matchQuery来完成模糊匹配,

搜索模糊的关键词使用matchPhraseQuery

对指定字段进行精确的分词搜索,适用于关键词精确搜索。

ES是否能在类型为text的字段的内部使用keyword,如果能这样做的含义是什么?

在Elasticsearch中,你可以在类型为"text"的字段内部使用"keyword"。

这种使用方式被称为"multi-fields"(多字段),它允许你在同一个字段上定义多个不同类型的子字段。
 当你在类型为"text"的字段上同时定义一个"keyword"子字段时,它的含义是:
1. "text"类型子字段:该子字段会对文本进行分析,将其拆分为单个词项,并应用分词器和过滤器等分析器组件。这样可以支持全文搜索和相关性评分。
2. "keyword"类型子字段:该子字段会将整个文本作为一个项进行索引和搜索,不进行分词和分析。这样可以实现精确匹配、排序和聚合操作。
 这种使用方式的好处是,你可以在同一个字段上同时支持全文搜索和精确匹配操作,而无需额外定义多个字段。例如,你可以使用"text"类型子字段进行全文搜索,并使用"keyword"类型子字段进行精确匹配或排序。
 以下是一个示例,展示如何在Elasticsearch中定义一个包含"text"和"keyword"子字段的字段:
json
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      }
    }
  }
}
在上面的示例中,"title"字段被定义为"text"类型,并包含一个名为"keyword"的"keyword"类型子字段。这样,你可以同时在"title"字段上进行全文搜索和精确匹配操作。
 总而言之,你可以在类型为"text"的字段内部使用"keyword"子字段,以实现同时支持全文搜索和精确匹配的功能。

实战:

字段

javascript">				"agent_name": {
					"type": "text",
					"fields": {
						"keyword": {
							"ignore_above": 256,
							"type": "keyword"
						}
					}
				},

要求精准匹配到agent_name为河南神龙公司的所有信息。

java">        // 指定索引
        request.indices("smsp_collect_info_new");
        // 构建查询条件
        SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();
        // 使用精准分词 查找
        searchSourceBuilder.query(QueryBuilders.termQuery("agent_name.keyword", "河南神龙公司"));
        //放入文档中
        request.source(searchSourceBuilder);
        //远程查询
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //获取结果
        SearchHit[] searchHits = response.getHits().getHits();
        for (SearchHit hit : searchHits) {
            System.out.println(hit.getSourceAsMap().get("agent_name"));
        }

这里的agent_name字段就是运用了多字段的思想/方式。

什么是ES多字段?

ES多字段(Multi-fields)是Elasticsearch中的一个概念,它允许在一个字段上定义多个不同类型的子字段。每个子字段可以根据不同的需求进行不同的处理和索引,以便在搜索和聚合时提供更灵活的功能。
 使用多字段的主要目的是在同一个字段上同时支持多种查询需求。例如,你可能想要在一个字段上进行全文搜索、精确匹配和排序等操作。通过使用多字段,你可以根据不同的查询需求定义不同类型的子字段,从而在每个子字段上使用适当的查询方式。
 多字段可以在映射(mapping)中定义。以下是一个示例,展示如何在Elasticsearch中定义一个包含多字段的字段:
json
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword"
          },
          "english": {
            "type": "text",
            "analyzer": "english"
          }
        }
      }
    }
  }
}
在上面的示例中,"title"字段被定义为"text"类型,并包含两个子字段:"keyword"和"english"。其中,"keyword"子字段是"keyword"类型,用于精确匹配和排序,而"english"子字段是"text"类型,并使用英文分析器进行全文搜索。
 通过使用多字段,你可以根据不同的查询需求选择适当的子字段进行搜索、排序和聚合,从而提供更灵活和准确的搜索体验。
 总而言之,ES多字段是在一个字段上定义多个不同类型的子字段,用于在不同的查询需求下提供灵活的搜索和聚合功能。

ES怎么实现聚合查询?

主要是通过AggregationBuilders来进行聚合条件的构建,然后通过aggregation方法将AggregationBuilders拼接到SearchSourceBuilder 中实现的。如果有子聚合是通过subaggregation方法进行拼装的。

聚合查询的类型

- Range Aggregation:按指定的范围对字段进行聚合,比如按价格范围聚合商品。

- Date Histogram Aggregation:按指定的时间间隔对日期字段进行聚合,比如按月份聚合销售数据。

- Histogram Aggregation:按指定的数值间隔对数值字段进行聚合,比如按价格区间聚合商品。

- Terms Aggregation:对字段进行词条聚合,类似于SQL中的GROUP BY操作。

- Avg Aggregation:计算字段的平均值。

- Sum Aggregation:计算字段的总和。

- Max Aggregation:计算字段的最大值。

- Min Aggregation:计算字段的最小值。

- Cardinality Aggregation:计算字段的基数(不重复值的数量)。

查询+分组聚合实战

java">public void GroupSearch() throws IOException {
        SearchRequest request = new SearchRequest();

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        request.indices("smsp_collect_info_new");
        // 模糊分词查询
        searchSourceBuilder.query(QueryBuilders.matchQuery("province", "河南"));
        // 分组聚合查询
        searchSourceBuilder.aggregation(AggregationBuilders
                .terms("your_agg_name")
                .field("agent_name.keyword")
                .subAggregation(AggregationBuilders.count("count_number")
                        // 指定返回的桶的最大数量为10000
                        .field("company.keyword")).size(10000));

        //放入文档中
        request.source(searchSourceBuilder);
        //远程查询
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        // 获取所有的桶
        Terms termsAggregation = response.getAggregations().get("your_agg_name");
        for (Terms.Bucket bucket : termsAggregation.getBuckets()) {
            // 获得每次聚合的key的值
            System.out.println("当前的key为:"+bucket.getKeyAsString());
            ValueCount countAggregation =bucket.getAggregations().get("count_number");
            System.out.println("当前键下的聚合属性的总和,"+countAggregation.getValue());
        }
    }

RestHighLevelClient的subAggregation是什么?干什么用的?

RestHighLevelClient的subAggregation是用于在Elasticsearch中进行嵌套聚合操作的功能。在Elasticsearch中,聚合是一种用于对数据进行分组、过滤和计算的功能,可以根据不同的聚合类型对字段进行统计、计算平均值、求和等操作。

subAggregation允许在一个聚合操作的结果上进行进一步的嵌套聚合操作。

通过使用subAggregation,可以对聚合结果进行更细粒度的分析和处理。

例如,可以在terms聚合的结果上进行子聚合,对每个聚合桶进行更深入的统计。

以下是一个使用RestHighLevelClient进行subAggregation的示例代码:

java">RestHighLevelClient client = new RestHighLevelClient(
        RestClient.builder(new HttpHost("localhost", 9200, "http")));
 SearchRequest searchRequest = new SearchRequest("your_index_name"); // 替换为实际的索引名
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
 // 添加主聚合
TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("my_terms_agg")
        .field("your_field_name"); // 替换为实际的字段名
 // 添加子聚合
MaxAggregationBuilder subAggregationBuilder = AggregationBuilders.max("my_max_agg")
        .field("your_nested_field_name"); // 替换为实际的嵌套字段名
aggregationBuilder.subAggregation(subAggregationBuilder);
 searchSourceBuilder.aggregation(aggregationBuilder);
searchRequest.source(searchSourceBuilder);
 try {
    SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
     // 解析聚合结果
    Terms termsAggregation = searchResponse.getAggregations().get("my_terms_agg");
    for (Terms.Bucket bucket : termsAggregation.getBuckets()) {
        String key = bucket.getKeyAsString();
        Max maxAggregation = bucket.getAggregations().get("my_max_agg");
        double max = maxAggregation.getValue();
         // 处理聚合结果
        System.out.println("Bucket Key: " + key);
        System.out.println("Max Value: " + max);
    }
} catch (IOException e) {
    e.printStackTrace();
}
 client.close();

什么是RestHighLevelClient的滚动查询?如何实现?

RestHighLevelClient的滚动查询是一种用于在Elasticsearch中检索大量数据的机制。它允许您通过多个请求迭代地获取结果集,而不是一次性获取所有结果。滚动查询适用于需要处理大量数据的情况,例如导出数据、数据分析等。
 与其他查询方式相比,滚动查询具有以下优势:
1. 可以处理大量数据:滚动查询适用于处理超过单个请求的结果集大小限制的情况。它允许您按需获取数据,而不会因为数据量过大而导致请求失败或性能下降。
2. 节省内存:滚动查询通过每次返回一小批结果并在服务器端维护滚动上下文来减少内存消耗。这使得在处理大量数据时,不需要将所有结果加载到内存中,从而节省了内存资源。
3. 支持持续查询:滚动查询的结果可以被持续使用,即使在处理期间索引中的数据发生了变化。您可以使用滚动上下文来保持查询的一致性,而不受索引更新的影响。
4. 支持并发处理:通过使用滚动查询,您可以并发地处理多个滚动上下文,从而提高查询的吞吐量和效率。
 需要注意的是,滚动查询也有一些限制和注意事项:
1. 滚动查询会占用服务器资源:由于滚动上下文需要在服务器端维护,因此会占用一定的内存和计算资源。在设计滚动查询时,需要考虑服务器的可用资源以及查询的并发性能。
2. 滚动查询的结果可能不是实时的:如果在滚动查询期间索引中的数据发生了变化,滚动查询的结果可能不会反映最新的数据。因此,在滚动查询中处理数据时,需要注意数据的一致性和实时性。
 总之,RestHighLevelClient的滚动查询是一种强大的机制,可以高效地处理大量数据。它提供了灵活的分批获取结果的方式,适用于需要处理大数据量的场景。

实现:

java">public void ScrollSearch() throws IOException {
        SearchRequest request = new SearchRequest();
        //失效时间为10min
        Scroll scroll = new Scroll(TimeValue.timeValueMinutes(10));
        //封存快照
        request.scroll(scroll);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        request.indices("smsp_collect_info_new");
        searchSourceBuilder.query(QueryBuilders.matchQuery("province", "黑龙江"));
        // 每次查询2000个,是滚动查询条数的步长
        searchSourceBuilder.size(2000);
        //放入文档中
        request.source(searchSourceBuilder);
        //远程查询
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHit[] searchHits = response.getHits().getHits();
        //处理第一次的响应结果
        for (SearchHit hit : searchHits) {
            String province = hit.getSourceAsMap().get("province").toString();
            System.out.println(province);
            // 处理每个查询结果
        }
        // 获取第一次的滚动id
        String scrollId = response.getScrollId();
        while (searchHits.length > 0) {
            // 每循环一次构建一个新的滚动请求。
            SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);
            scrollRequest.scroll(TimeValue.timeValueMinutes(1));
            response = client.scroll(scrollRequest, RequestOptions.DEFAULT);
            // 获取新的滚动请求的滚动id
            scrollId = response.getScrollId();
            searchHits = response.getHits().getHits();
            // 处理下一批查询结果
            for (SearchHit hit : searchHits) {
                String province = hit.getSourceAsMap().get("province").toString();
                System.out.println(province);
                // 处理每个查询结果
            }
        }

    }

ES构建简单搜索

使用模糊匹配

java">public void simpleSearch() throws IOException {
        SearchRequest request = new SearchRequest();
        // 指定索引
        request.indices("smsp_collect_info_new");
        // 构建查询条件 查询某城市
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchQuery("city", "郑州"));
        //放入文档中
        request.source(searchSourceBuilder);
        //远程查询
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //获取结果
        SearchHit[] searchHits = response.getHits().getHits();
        for (SearchHit hit : searchHits) {
            System.out.println(hit.getSourceAsMap().get("city"));
        }
    }

 使用精准匹配

java">    // 单条件精准查询
    public void simpleSearchUseTerm() throws IOException {
        SearchRequest request = new SearchRequest();
        // 指定索引
        request.indices("smsp_collect_info_new");
        // 构建查询条件 查询某城市
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 使用精准分词 查找
        searchSourceBuilder.query(QueryBuilders.termQuery("agent_name.keyword", "河南神龙公司"));
        //放入文档中
        request.source(searchSourceBuilder);
        //远程查询
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //获取结果
        SearchHit[] searchHits = response.getHits().getHits();
        for (SearchHit hit : searchHits) {
            System.out.println(hit.getSourceAsMap().get("agent_name"));
        }
    }

 

 


http://www.niftyadmin.cn/n/1404435.html

相关文章

L2-020 功夫传人 (25 分)(详解)

这道题大一上学期校内天梯选拔的时候遇到过,但是没有学过数据结构,就是再用循环和一个非常大的二位数组去做,结果有几个测试点段错误,还有运行超时之类的,得了十几分后来这道题就没怎么看过,现在该上大二了…

表插入排序算法及C语言实现(看了无师自通)

前面章节中所介绍到的三种插入排序算法,其基本结构都采用数组的形式进行存储,因而无法避免排序过程中产生的数据移动的问题。如果想要从根本上解决只能改变数据的存储结构,改用链表存储。 表插入排序,即使用链表的存储结构对数据进行插入排序。在对记录按照其关键字进行排序…

2-路插入排序算法详解(C语言实现)

2-路插入排序算法是在折半插入排序的基础上对其进行改进,减少其在排序过程中移动记录的次数从而提高效率。 具体实现思路为:另外设置一个同存储记录的数组大小相同的数组 d,将无序表中第一个记录添加进 d[0] 的位置上,然后从无序表中第二个记录开始,同 d[0] 作比较:如果该…

L2-022 重排链表 (25 分)

这道题其实不难,不妨定义一个结构体数组,把下标当作链表地址,每个结构体里面存放当前地址,下一个节点地址,以及数据,然后遍历整条链表,把遍历过程中链表的每一个节点都放在vector中,…

哈希表(散列表)及哈希表处理冲突的方法

前面介绍了静态查找表以及动态查找表中的一些查找方法,其查找的过程都无法避免同查找表中的数据进行比较,查找算法的效率很大程度取决于同表中数据的查找次数。 而本节所介绍的哈希表可以通过关键字直接找到数据的存储位置,不需要进行任何的比较,其查找的效率相较于前面所介…

L2-023 图着色问题 (25 分)

做这道题有一点需要注意&#xff0c;我一开始以为题目给的图一定是连通图&#xff0c;没有在dfs外套for循环&#xff0c;结果有一个测试点过不去&#xff0c;最后尝试着加上后就对了。 #include<iostream> #include<vector> #include<set> #include<cstr…

二叉排序树(二叉查找树)及C语言实现

前几节介绍的都是有关静态查找表的相关知识,从本节开始介绍另外一种查找表——动态查找表。 动态查找表中做查找操作时,若查找成功可以对其进行删除;如果查找失败,即表中无该关键字,可以将该关键字插入到表中。 动态查找表的表示方式有多种,本节介绍一种使用树结构表示动…

L2-024 部落 (25 分)

这是一道非常简单的并查集问题&#xff0c;相信无需多言&#xff0c;具体大家看代码。 #include<iostream> #include<set> using namespace std; int f[10004]; void unit(void) {for(int i0;i<10003;i)f[i]i; } int find(int x) {if(f[x]!x)return f[x]find(…