ElasticSearch搜索-结构化数据

本篇主要讲一下对于结构化字段的搜索,如:布尔、日期和数字型数据。其中文本的枚举值也可以作为结构化数据,如:东、西、南、北;红、绿、蓝等。

结构化的数据可以对其进行逻辑操作,包括数据范围,比较大小等。结构化的文本可以做到精确匹配或部分匹配(Term查询、Prefix查询)。结构化数据只有"是"/“否”两个值,可以根据场景需要,决定是否对其进行打分。

下面我们先重新写入一些数据,如下所示:

DELETE /cars

POST /cars/_bulk
{ "index": { "_id": 1 }}
{ "carId" : "2020-SH-PD-001","name":"Bluck","address":"上海浦东","regist":true,"buydate":"2020-02-10","price":219000 }
{ "index": { "_id": 2 }}
{ "carId" : "2019-BJ-CY-109","name":"Benz","address":"北京朝阳","regist":false,"buydate":"2020-05-12","price":508000 }
{ "index": { "_id": 3 }}
{ "carId" : "2020-NJ-QX-001","name":"BMW","address":"南京栖霞","regist":true,"buydate":"2017-12-12","price":483000 }

然后查看一下 mapping 的定义,如下:

GET /cars/_mapping

{
  "cars" : {
    "mappings" : {
      "properties" : {
        "address" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "buydate" : {
          "type" : "date"
        },
        "carId" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "name" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "price" : {
          "type" : "long"
        },
        "regist" : {
          "type" : "boolean"
        }
      }
    }
  }
}

布尔类型

当使用下面条件进行查询时,会发现对 Boolean 类型进行查询时是有评分的。

POST /cars/_search
{
  "profile": "true", 
  "explain": true, 
  "query": {
    "term": {
      "regist":true
    }
  }
}

在某些场景下,如果不需要对Boolean 进行算分,可以通过 constant Score,将Query 转换为 Filter,不用算分以提升性能。

POST /cars/_search
{
  "profile": "true", 
  "explain": true, 
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "regist":true
        }
      },
      "boost": 1.2
    }
  }
}

数字类型

首先可以通过 Term 查询,对数字类型做精确匹配。如对 price = 219000 的汽车进行查询:

POST /cars/_search
{
  "profile": "true", 
  "explain": true, 
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "price":219000
        }
      },
      "boost": 1.2
    }
  }
}

对于数字类型还可以进行 Terms 查询:

POST /cars/_search
{
  "profile": "true",
  "explain": true,
  "query": {
    "constant_score": {
      "filter": {
        "terms": {
          "price": [
            219000,
            483000
          ]
        }
      },
      "boost": 1.2
    }
  }
}

还有 Range 查询,查询价格区间在 40万-60万之间的汽车列表。

POST /cars/_search
{
  "profile": "true",
  "explain": true,
  "query": {
    "constant_score": {
      "filter": {
        "range": {
          "price": {
            "gte": 400000,
            "lte": 600000
          }
        }
      },
      "boost": 1.2
    }
  }
}

日期类型

对于日期类型,其简化标识和其他编程语言中的类似,如下所示:


如:查询2年前之后购买的汽车:

POST /cars/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "range": {
          "buydate": {
            // 从当前时间减2年
            "gte": "now-2y"
          }
        }
      }
    }
  }
}

exists 查询

下面的查询的意思是:过滤存在字段 name 的文档。

POST /cars/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "exists": {
          "field": "name"
        }
      }
    }
  }
}


参考:《ElasticSearch技术解析与实战》、《极客时间:ElasticSearch核心技术与实战》