• 浅谈Elasticsearch查询和搜索


    Elasticsearch查询和搜索

    Elasticsearch是一个分布式、实时的搜索和分析引擎,广泛应用于全文搜索、日志分析、实时数据分析等场景。Elasticsearch提供了丰富的查询和搜索功能,如查询DSL、过滤、排序、分页、高亮和聚合等。本文将详细介绍如何在Elasticsearch中使用这些功能。

    1. 查询DSL

    Elasticsearch使用查询DSL(Domain Specific Language)来构建查询。查询DSL是一种基于JSON的查询语言,允许您以简洁、易读的方式构建复杂的查询。

    1.1 基本查询

    match查询是一个全文搜索查询,用于在一个或多个字段中搜索文本。以下是一个match查询示例:

    {
      "query": {
        "match": {
          "title": "Elasticsearch"
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在此示例中,我们构建了一个match查询,用于搜索title字段中包含"Elasticsearch"的文档。

    要在Elasticsearch中执行查询,您可以使用_searchAPI。以下是一个使用curl命令执行查询的示例:

    curl -X GET "localhost:9200/my_index/_search" -H 'Content-Type: application/json' -d'
    {
      "query": {
        "match": {
          "title": "Elasticsearch"
        }
      }
    }
    '
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1.1.1 Multi-match查询

    multi_match查询允许您在多个字段中执行全文搜索。以下是一个multi_match查询示例:

    {
      "query": {
        "multi_match": {
          "query": "Elasticsearch",
          "fields": ["title", "content"]
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在此示例中,我们构建了一个multi_match查询,用于搜索titlecontent字段中包含"Elasticsearch"的文档。

    1.1.2 Term查询

    term查询用于在一个字段中搜索精确值。以下是一个term查询示例:

    {
      "query": {
        "term": {
          "status.keyword": "published"
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在此示例中,我们构建了一个term查询,用于搜索status.keyword字段中值为"published"的文档。

    1.1.3 Range查询

    range查询用于在一个字段中搜索范围内的值。以下是一个range查询示例:

    {
      "query": {
        "range": {
          "publish_date": {
            "gte": "2021-01-01",
            "lte": "2021-12-31"
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在此示例中,我们构建了一个range查询,用于搜索publish_date字段中值在"2021-01-01"到"2021-12-31"之间的文档。

    1.2 复合查询

    复合查询允许您组合多个查询,以构建更复杂的查询条件。

    1.2.1 Bool查询

    bool查询允许您组合多个查询,使用逻辑运算符(如mustshouldmust_notfilter)来定义查询条件。以下是一个bool查询示例:

    {
      "query": {
        "bool": {
          "must": {
            "match": {
              "title": "Elasticsearch"
            }
          },
          "filter": {
            "range": {
              "publish_date": {
                "gte": "2021-01-01"
              }
            }
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在此示例中,我们构建了一个bool查询,用于搜索title字段中包含"Elasticsearch"且publish_date字段大于等于"2021-01-01"的文档。

    1.2.2 Disjunction Max查询(Dis Max查询)

    dis_max查询允许您在多个查询中选择最高得分的查询结果。以下是一个dis_max查询示例:

    {
      "query": {
        "dis_max": {
          "queries": [
            {
              "match": {
                "title": "Elasticsearch"
              }
            },
            {
              "match": {
                "content": "Elasticsearch"
              }
            }
          ]
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在此示例中,我们构建了一个dis_max查询,用于搜索titlecontent字段中包含"Elasticsearch"的文档。查询结果将根据最高得分的查询进行排序。

    1.3 嵌套查询

    嵌套查询用于查询包含嵌套对象的文档。假设我们有一个包含comments嵌套对象的文档,每个评论都有一个authorcontent字段。以下是一个嵌套查询示例:

    {
      "query": {
        "nested": {
          "path": "comments",
          "query": {
            "bool": {
              "must": [
                {
                  "match": {
                    "comments.author": "John Doe"
                  }
                },
                {
                  "match": {
                    "comments.content": "Elasticsearch"
                  }
                }
              ]
            }
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在此示例中,我们构建了一个嵌套查询,用于搜索comments.author字段为"John Doe"且comments.content字段包含"Elasticsearch"的文档。

    1.4 聚合查询

    聚合查询允许您对查询结果进行分组和统计。要在查询中添加聚合,您可以使用aggs参数。以下是一个聚合示例:

    {
      "query": {
        "match": {
          "title": "Elasticsearch"
        }
      },
      "aggs": {
        "by_category": {
          "terms": {
            "field": "category.keyword"
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在此示例中,我们添加了一个名为by_category的聚合,该聚合按category.keyword字段对查询结果进行分组。terms聚合用于计算每个类别中的文档数量。

    要获取聚合结果,您可以在响应中查看aggregations字段。以下是一个聚合结果示例:

    {
      ...
      "aggregations": {
        "by_category": {
          "buckets": [
            {
              "key": "category1",
              "doc_count": 10
            },
            {
              "key": "category2",
              "doc_count": 5
            }
          ]
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在此示例中,我们可以看到每个类别中的文档数量。例如,category1中有10个文档,category2中有5个文档。

    2. 过滤

    2.1 过滤与查询的区别

    在Elasticsearch中,查询和过滤有以下主要区别:

    • 查询(Query):主要用于全文搜索,会计算文档的相关性得分(relevance score)。
    • 过滤(Filter):主要用于精确匹配,不计算相关性得分,只返回满足条件的文档。过滤结果会被缓存,因此过滤通常比查询更快。

    2.2 使用过滤

    过滤允许您根据特定条件筛选查询结果。要在查询中添加过滤条件,您可以使用bool查询的filter子句。以下是一个过滤示例:

    {
      "query": {
        "bool": {
          "must": {
            "match": {
              "title": "Elasticsearch"
            }
          },
          "filter": {
            "range": {
              "publish_date": {
                "gte": "2021-01-01"
              }
            }
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在此示例中,我们添加了一个range过滤器,用于筛选publish_date字段大于等于"2021-01-01"的文档。

    2.3 常见的过滤类型

    以下是一些常见的过滤类型:

    2.3.1 Term过滤

    term过滤用于在一个字段中搜索精确值。以下是一个term过滤示例:

    {
      "query": {
        "bool": {
          "filter": {
            "term": {
              "status.keyword": "published"
            }
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在此示例中,我们构建了一个term过滤器,用于筛选status.keyword字段中值为"published"的文档。

    2.3.2 Range过滤

    range过滤用于在一个字段中搜索范围内的值。以下是一个range过滤示例:

    {
      "query": {
        "bool": {
          "filter": {
            "range": {
              "publish_date": {
                "gte": "2021-01-01",
                "lte": "2021-12-31"
              }
            }
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在此示例中,我们构建了一个range过滤器,用于筛选publish_date字段中值在"2021-01-01"到"2021-12-31"之间的文档。

    2.3.3 Exists过滤

    exists过滤用于筛选包含特定字段的文档。以下是一个exists过滤示例:

    {
      "query": {
        "bool": {
          "filter": {
            "exists": {
              "field": "author"
            }
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在此示例中,我们构建了一个exists过滤器,用于筛选包含author字段的文档。

    2.3.4 Bool过滤

    bool过滤允许您组合多个过滤条件,使用逻辑运算符(如mustshouldmust_not)来定义过滤条件。以下是一个bool过滤示例:

    {
      "query": {
        "bool": {
          "filter": [
            {
              "term": {
                "status.keyword": "published"
              }
            },
            {
              "range": {
                "publish_date": {
                  "gte": "2021-01-01"
                }
              }
            }
          ]
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在此示例中,我们构建了一个bool过滤器,用于筛选status.keyword字段中值为"published"且publish_date字段大于等于"2021-01-01"的文档。

    2.3.5 Geo距离过滤

    geo_distance过滤用于筛选距离给定地理坐标一定范围内的文档。以下是一个geo_distance过滤示例:

    {
      "query": {
        "bool": {
          "filter": {
            "geo_distance": {
              "distance": "100km",
              "location": {
                "lat": 40.7128,
                "lon": -74.0060
              }
            }
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在此示例中,我们构建了一个geo_distance过滤器,用于筛选距离纬度40.7128、经度-74.0060的地理坐标100公里以内的文档。

    2.4 组合查询和过滤

    在实际应用中,您可能需要根据多个条件对文档进行查询和过滤。以下是一个组合查询和过滤的示例:

    {
      "query": {
        "bool": {
          "must": {
            "match": {
              "title": "Elasticsearch"
            }
          },
          "filter": [
            {
              "term": {
                "status.keyword": "published"
              }
            },
            {
              "range": {
                "publish_date": {
                  "gte": "2021-01-01"
                }
              }
            }
          ]
        }
      }
    }
    
    • 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

    在此示例中,我们构建了一个bool查询,用于搜索title字段中包含"Elasticsearch"的文档。同时,我们添加了两个过滤器,用于筛选status.keyword字段中值为"published"且publish_date字段大于等于"2021-01-01"的文档。

    3. 排序

    3.1 基本排序

    在 Elasticsearch 中,我们可以使用 _sort 参数来指定排序字段。例如,我们有一个名为 products 的索引,其中包含了一些商品信息,我们可以根据商品的价格(price)进行升序排序:

    GET /products/_search
    {
      "query": {
        "match_all": {}
      },
      "sort": [
        {
          "price": {
            "order": "asc"
          }
        }
      ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这个例子中,我们使用了 match_all 查询来获取所有的商品,然后通过 sort 参数指定了按照 price 字段进行升序排序。order 参数可以接受 asc(升序)和 desc(降序)两个值。

    3.2 多字段排序

    有时候,我们需要根据多个字段进行排序。在 Elasticsearch 中,我们可以在 sort 参数中指定多个排序字段。例如,我们可以先根据商品的价格进行升序排序,然后再根据商品的评分(rating)进行降序排序:

    GET /products/_search
    {
      "query": {
        "match_all": {}
      },
      "sort": [
        {
          "price": {
            "order": "asc"
          }
        },
        {
          "rating": {
            "order": "desc"
          }
        }
      ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这个例子中,我们在 sort 参数中指定了两个排序字段,分别是 pricerating。Elasticsearch 会先根据 price 进行排序,然后再根据 rating 进行排序。

    3.3 按照距离排序

    Elasticsearch 支持按照地理位置进行排序。例如,我们有一个名为 shops 的索引,其中包含了一些商店的信息,我们可以根据商店的位置(location)和用户的位置进行排序:

    GET /shops/_search
    {
      "query": {
        "match_all": {}
      },
      "sort": [
        {
          "_geo_distance": {
            "location": {
              "lat": 40.715,
              "lon": -73.988
            },
            "order": "asc",
            "unit": "km"
          }
        }
      ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这个例子中,我们使用了 _geo_distance 排序,它会根据商店的位置(location)和用户的位置(经纬度)计算距离,并按照距离进行排序。order 参数用于指定排序方式,unit 参数用于指定距离的单位。

    3.4 按照评分排序

    在 Elasticsearch 中,我们可以使用 _score 参数来按照文档的评分进行排序。例如,我们可以根据商品的名称(name)进行搜索,并按照评分进行降序排序:

    GET /products/_search
    {
      "query": {
        "match": {
          "name": "iphone"
        }
      },
      "sort": [
        {
          "_score": {
            "order": "desc"
          }
        }
      ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这个例子中,我们使用了 match 查询来搜索商品名称中包含 iphone 的商品,然后通过 sort 参数指定了按照评分进行降序排序。

    3.5 自定义排序

    Elasticsearch 支持使用脚本(Script)来自定义排序。例如,我们可以根据商品的价格(price)和销量(sales)计算一个综合得分,并按照综合得分进行排序:

    GET /products/_search
    {
      "query": {
        "match_all": {}
      },
      "sort": [
        {
          "_script": {
            "type": "number",
            "script": {
              "source": "doc['price'].value * 0.8 + doc['sales'].value * 0.2"
            },
            "order": "desc"
          }
        }
      ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这个例子中,我们使用了 _script 排序,它允许我们使用脚本来计算一个自定义的排序值。在这里,我们使用了一个简单的公式 doc['price'].value * 0.8 + doc['sales'].value * 0.2 来计算综合得分,其中 price 占 80%,sales 占 20%。然后我们通过 order 参数指定了按照综合得分进行降序排序。

    需要注意的是,使用脚本排序可能会影响查询性能,因此在实际应用中需要权衡性能和灵活性。

    3.6 排序缺失值处理

    在 Elasticsearch 中,如果排序字段中存在缺失值,我们可以使用 missing 参数来指定如何处理这些缺失值。例如,我们可以将缺失的价格(price)视为最低价格:

    GET /products/_search
    {
      "query": {
        "match_all": {}
      },
      "sort": [
        {
          "price": {
            "order": "asc",
            "missing": "_first"
          }
        }
      ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这个例子中,我们使用了 missing 参数,并将其设置为 _first,这意味着缺失值将被视为最小值,因此在升序排序时,它们将排在最前面。我们还可以将 missing 设置为 _last(将缺失值视为最大值)或者一个具体的数值。

    4. 分页

    4.1 基本分页

    在 Elasticsearch 中,我们可以使用 fromsize 参数来实现分页。from 参数表示起始文档的位置(从 0 开始),size 参数表示每页文档的数量。例如,我们有一个名为 products 的索引,其中包含了一些商品信息,我们可以获取第一页的商品(每页 10 个):

    GET /products/_search
    {
      "query": {
        "match_all": {}
      },
      "from": 0,
      "size": 10
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这个例子中,我们使用了 match_all 查询来获取所有的商品,然后通过 fromsize 参数指定了分页信息。这里 from 为 0,表示从第一个文档开始,size 为 10,表示每页包含 10 个文档。

    4.2 深度分页

    在 Elasticsearch 中,我们可以通过调整 from 参数的值来实现深度分页。例如,我们可以获取第二页的商品(每页 10 个):

    GET /products/_search
    {
      "query": {
        "match_all": {}
      },
      "from": 10,
      "size": 10
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这个例子中,我们将 from 参数的值设置为 10,表示从第 11 个文档开始。其他参数保持不变。

    需要注意的是,深度分页可能会影响查询性能。因为 Elasticsearch 需要跳过 from 参数指定的文档数量,这可能会导致较高的内存和 CPU 消耗。在实际应用中,我们应该尽量避免使用过大的 from 值。

    4.3 分页限制

    Elasticsearch 默认允许查询的最大文档数量为 10000。这意味着,如果我们使用 fromsize 参数进行分页,from + size 的值不能超过 10000。例如,以下查询将会失败:

    GET /products/_search
    {
      "query": {
        "match_all": {}
      },
      "from": 9900,
      "size": 200
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这个例子中,from + size 的值为 10100,超过了默认的最大文档数量。为了解决这个问题,我们可以使用 index.max_result_window 参数来调整最大文档数量。例如,我们可以将其设置为 20000:

    PUT /products/_settings
    {
      "index": {
        "max_result_window": 20000
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    需要注意的是,增加最大文档数量可能会导致更高的内存和 CPU 消耗。在实际应用中,我们应该根据需求和资源情况来调整这个参数。

    4.4 搜索结果遍历

    对于大量数据的遍历,我们可以使用 Elasticsearch 的 Scroll API。Scroll API 可以在一定时间内保留查询快照,从而避免深度分页带来的性能问题。以下是一个使用 Scroll API 的例子:

    # 初始化 scroll
    GET /products/_search?scroll=1m
    {
      "query": {
        "match_all": {}
      },
      "size": 10
    }
    
    ```json
    # 使用 scroll_id 获取下一页结果
    GET /_search/scroll
    {
      "scroll": "1m",
      "scroll_id": "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndU..."
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这个例子中,我们首先使用 scroll 参数初始化了一个 scroll 上下文,并设置了一个 1 分钟的保留时间。然后,我们使用 size 参数指定每次获取 10 个文档。在获取下一页结果时,我们需要使用上一次查询返回的 scroll_id。这个过程可以重复进行,直到所有文档都被遍历完。

    需要注意的是,当遍历完成后,我们应该及时清除 scroll 上下文,以释放资源:

    DELETE /_search/scroll
    {
      "scroll_id": "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndU..."
    }
    
    • 1
    • 2
    • 3
    • 4

    4.5 分页与排序

    在使用 Elasticsearch 进行分页时,我们通常需要对查询结果进行排序。例如,我们可以根据商品的价格(price)进行升序排序,并获取第一页的商品(每页 10 个):

    GET /products/_search
    {
      "query": {
        "match_all": {}
      },
      "sort": [
        {
          "price": {
            "order": "asc"
          }
        }
      ],
      "from": 0,
      "size": 10
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这个例子中,我们使用了 sort 参数来指定排序字段,并通过 fromsize 参数指定了分页信息。这样,我们可以获取按照价格排序的商品列表,并进行分页展示。

    5. 高亮

    5.1 基本高亮

    在 Elasticsearch 中,我们可以使用 highlight 参数来实现高亮。例如,我们有一个名为 articles 的索引,其中包含了一些文章信息,我们可以根据文章的标题(title)和内容(content)进行搜索,并高亮匹配的关键词:

    GET /articles/_search
    {
      "query": {
        "multi_match": {
          "query": "Elasticsearch",
          "fields": ["title", "content"]
        }
      },
      "highlight": {
        "fields": {
          "title": {},
          "content": {}
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这个例子中,我们使用了 multi_match 查询来搜索标题和内容中包含 “Elasticsearch” 的文章,然后通过 highlight 参数指定了高亮字段。这里我们指定了 titlecontent 两个字段进行高亮。

    查询结果中,每个文档都会包含一个 highlight 字段,其中包含了高亮后的文本片段。默认情况下,高亮的关键词会被包裹在 标签中。

    5.2 高亮标签

    在 Elasticsearch 中,我们可以自定义高亮标签。例如,我们可以将高亮关键词包裹在 标签中:

    GET /articles/_search
    {
      "query": {
        "multi_match": {
          "query": "Elasticsearch",
          "fields": ["title", "content"]
        }
      },
      "highlight": {
        "pre_tags": [""],
        "post_tags": [""],
        "fields": {
          "title": {},
          "content": {}
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这个例子中,我们使用了 pre_tagspost_tags 参数来指定高亮标签。这里我们将高亮关键词包裹在 标签中。

    5.3 高亮片段

    在 Elasticsearch 中,我们可以控制高亮片段的数量和长度。例如,我们可以设置每个字段最多返回 3 个高亮片段,每个片段最多包含 150 个字符:

    GET /articles/_search
    {
      "query": {
        "multi_match": {
          "query": "Elasticsearch",
          "fields": ["title", "content"]
        }
      },
      "highlight": {
        "number_of_fragments": 3,
        "fragment_size": 150,
        "fields": {
          "title": {},
          "content": {}
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这个例子中,我们使用了 number_of_fragmentsfragment_size 参数来控制高亮片段。这里我们设置了每个字段最多返回 3 个高亮片段,每个片段最多包含 150 个字符。

    5.4 高亮类型

    Elasticsearch 支持多种高亮类型,包括 plain(默认)、postingsfvh。不同的高亮类型在性能和功能上有所差异。例如,我们可以使用 postings 高亮类型来提高高亮性能:

    GET /articles/_search
    {
      "query": {
        "multi_match": {
          "query": "Elasticsearch",
          "fields": ["title", "content"]
        }
      },
      "highlight": {
        "type": "postings",
        "fields": {
          "title": {},
          "content": {}
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这个例子中,我们使用了 type 参数来指定高亮类型。这里我们将高亮类型设置为 postings。需要注意的是,使用 postings 高亮类型时,我们需要在索引设置中启用 term_vector

    PUT /articles
    {
      "mappings": {
        "properties": {
          "title": {
            "type": "text",
            "term_vector": "with_positions_offsets"
          },
          "content": {
            "type": "text",
            "term_vector": "with_positions_offsets"
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这个例子中,我们在创建索引时为 titlecontent 字段启用了 term_vector。这样,我们就可以使用 postings 高亮类型来提高高亮性能。

    5.5 高亮查询

    在某些情况下,我们可能需要根据不同的查询条件来高亮文本。Elasticsearch 支持使用 highlight_query 参数来指定高亮查询。例如,我们可以根据文章的标题(title)和内容(content)进行搜索,但只高亮标题中的关键词:

    GET /articles/_search
    {
      "query": {
        "multi_match": {
          "query": "Elasticsearch",
          "fields": ["title", "content"]
        }
      },
      "highlight": {
        "fields": {
          "title": {
            "highlight_query": {
              "match": {
                "title": "Elasticsearch"
              }
            }
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这个例子中,我们使用了 highlight_query 参数来指定高亮查询。这里我们设置了只高亮标题中的关键词。

    6. 聚合

    6.1 基本聚合

    在 Elasticsearch 中,我们可以使用 aggs 参数来实现聚合。例如,我们有一个名为 sales 的索引,其中包含了一些销售记录,我们可以根据商品类别(category)进行分组,并计算每个类别的销售总额(amount):

    GET /sales/_search
    {
      "size": 0,
      "aggs": {
        "category_stats": {
          "terms": {
            "field": "category.keyword"
          },
          "aggs": {
            "total_amount": {
              "sum": {
                "field": "amount"
              }
            }
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这个例子中,我们使用了 terms 聚合来根据商品类别进行分组,然后使用了 sum 聚合来计算每个类别的销售总额。这里我们将聚合结果命名为 category_stats

    查询结果中,会包含一个名为 aggregations 的字段,其中包含了聚合结果。在这个例子中,我们可以获取每个类别的销售总额。

    6.2 按照范围聚合

    在 Elasticsearch 中,我们可以使用 range 聚合来根据指定的范围进行分组。例如,我们可以根据销售额(amount)的范围进行分组,统计不同范围内的销售记录数量:

    GET /sales/_search
    {
      "size": 0,
      "aggs": {
        "amount_ranges": {
          "range": {
            "field": "amount",
            "ranges": [
              { "to": 100 },
              { "from": 100, "to": 500 },
              { "from": 500 }
            ]
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这个例子中,我们使用了 range 聚合来根据销售额的范围进行分组。这里我们定义了三个范围:小于 100、100 到 500、大于 500。查询结果中,我们可以获取不同范围内的销售记录数量。

    6.3 日期聚合

    在 Elasticsearch 中,我们可以使用 date_histogram 聚合来根据日期进行分组。例如,我们可以根据销售日期(date)进行分组,统计每个月的销售总额(amount):

    GET /sales/_search
    {
      "size": 0,
      "aggs": {
        "monthly_sales": {
          "date_histogram": {
            "field": "date",
            "calendar_interval": "month"
          },
          "aggs": {
            "total_amount": {
              "sum": {
                "field": "amount"
              }
            }
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这个例子中,我们使用了 date_histogram 聚合来根据销售日期进行分组。这里我们设置了 calendar_interval 参数为 month,表示按照月份进行分组。查询结果中,我们可以获取每个月的销售总额。

    6.4 嵌套聚合

    在 Elasticsearch 中,我们可以使用嵌套聚合来实现多层分组。例如,我们可以先根据商品类别(category)进行分组,然后再根据销售员(salesperson)进行分组,统计每个类别下每个销售员的销售总额(amount):

    GET /sales/_search
    {
      "size": 0,
      "aggs": {
        "category_stats": {
          "terms": {
            "field": "category.keyword"
          },
          "aggs": {
            "salesperson_stats": {
              "terms": {
                "field": "salesperson.keyword"
              },
              "aggs": {
                "total_amount": {
                  "sum": {
                    "field": "amount"
                  }
                }
              }
            }
          }
        }
      }
    }
    
    • 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

    在这个例子中,我们首先使用了 terms 聚合来根据商品类别进行分组,然后在每个类别下再使用 terms 聚合根据销售员进行分组。最后,我们使用了 sum 聚合来计算每个类别下每个销售员的销售总额。查询结果中,我们可以获取多层分组的统计信息。

    6.5 按照过滤条件聚合

    在 Elasticsearch 中,我们可以使用 filter 聚合来根据过滤条件进行分组。例如,我们可以根据销售员(salesperson)为 “Alice” 的条件进行过滤,统计满足条件的销售总额(amount):

    GET /sales/_search
    {
      "size": 0,
      "aggs": {
        "alice_sales": {
          "filter": {
            "term": {
              "salesperson.keyword": "Alice"
            }
          },
          "aggs": {
            "total_amount": {
              "sum": {
                "field": "amount"
              }
            }
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这个例子中,我们使用了 filter 聚合来根据销售员为 “Alice” 的条件进行过滤。然后我们使用了 sum 聚合来计算满足条件的销售总额。查询结果中,我们可以获取 “Alice” 的销售总额。

    总结

    本文详细介绍了Elasticsearch的查询和搜索功能,包括查询DSL、过滤、排序、分页、高亮和聚合等。通过使用这些功能,您可以构建复杂的查询和分析,以满足各种业务场景和需求。希望本文能为您提供有关如何在Elasticsearch中使用查询和搜索功能的有用信息。

  • 相关阅读:
    蓝桥杯---附近最小(典型的滑动窗口类型问题)
    AE-如何制作湖面水波纹波动的效果
    274. H 指数
    2021年06月 Scratch(二级)真题解析#中国电子学会#全国青少年软件编程等级考试
    【深度学习21天学习挑战赛】备忘篇:我们的神经网模型到底长啥样?——model.summary()详解
    【每日一题】LFU 缓存
    JAVA开发管理(敏捷如何解决实际痛点问题)
    单片机-LED介绍
    Python-数据结构-序列
    0 基础 Java 自学之路(3)
  • 原文地址:https://blog.csdn.net/weixin_59801183/article/details/134268902