es03-搜索-过滤排序


es03-搜索-过滤排序

就像在学习mysql的时候,学习查询语句比其他语句花费的时间要多,es的查询语句也是如此。

文档的搜索

URL参数条件搜索

  • q:使用某个字段来进行查询,例如q:book_name=book,就是根据book_name中是否有book来- 进行搜索。
  • sort:使用某个字段来进行排序,例如sort=cost:desc,就是根据cost字段来进行降序desc排序。
  • 其他:fileds,timeout,analyzer【这些参数留在请求体搜索中讲】
  • 不带参数时,为“全搜索”
  • 多个参数使用&&拼接

例子

GET /douban/book/_search?q=book_summary:character
GET /douban/book/_search?q=book_author:Milan
GET /douban/book/_search?q=book_summary:a
GET /douban/book/_search?q=book_summary:a&&sort=book_pages:desc
GET /douban/book/_search?q=book_summary:a&&q=book_author:Milan
【值得注意的是,请先不要对text类型的数据进行排序,这会影响搜索,对整数排序即可,后面会再细讲】

请求体参数

语法和例子

//全搜索
GET /index/type/_search
GET /douban/book/_search

//全搜索
GET /index/type/_search
{
  "query": {
    "match_all": {}
  }
}
GET /douban/book/_search
{
  "query": {
    "match_all": {}
  }
}

// 查询指定字段的数据(全文搜索,如果搜索值有多个词,仅匹配一个词的结果也可以查询出来):
GET /index/type/_search
{
  "query": {
    "match": {
      "字段名": "搜索值"
    }
  }
}
GET /douban/book/_search
{
  "query": {
    "match": {
      "book_name": "A The"
    }
  }
}


// 使用同一搜索值搜索多个字段:
GET /index/type/_search
{
  "query": {
    "multi_match": {
      "query": "搜索值",
      "fields": [
        "搜索的字段1","搜索的字段2"]
    }
  }
}
GET /douban/book/_search
{
  "query": {
    "multi_match": {
      "query": "A",
      "fields": [
        "book_name","book_summary"]
    }
  }
}

// 短语查询:【搜索值必须完全匹配,不会把搜索值拆分来搜索】
GET /index/type/_search
{
  "query": {
    "match_phrase": {
      "字段": "搜索值"
    }
  }
}
GET /douban/book/_search
{
  "query": {
    "match_phrase": {
      "book_summary": "a character"
    }
  }
}

// 字段过滤,查询的结果只显示指定字段
GET /product/book/_search
{
  "query": {
    "查询条件"
  },
  "_source": [
    "显示的字段1",
    "显示的字段2"
    ]
}
GET /douban/book/_search
{
  "query": {
    "match": {
      "book_name": "Story"
    }
  },
  "_source": [
    "book_name",
    "book_id"
    ]
}

// 高亮查询:【根据查询的关键字来进行高亮,高亮的结果会显示在返回结果的会自动在返回结果中的highlight中,关键字会被加上<em>标签】
// 如果想要多字段高亮,也需要进行多字段搜索
GET /index/book/_search
{
  "query": {
    "查询条件"
  },
  "highlight": {
    "fields": {
      "高亮的字段名1": {}
    }
  }
}
GET /douban/book/_search
{
  "query": {
    "match": {
      "book_summary": "Story"
    }
  },
  "highlight": {
    "fields": {
      "book_summary":{}
    }
  }
}
GET /douban/book/_search
{
  "query": {
    "multi_match": {
      "query": "Story",
      "fields": [
        "book_name","book_summary"]
    }

  },
  "highlight": {
    "fields": {
      "book_summary":{},
      "book_name":{}
    }
  }
}
  • 前置知识:对于条件拼接,在SQL中有and,or,not,在ElasticSearch不太一样,下面逐一讲解:

  • bool:用来表明里面的语句是多条件的组合,用来包裹多个条件。

  • should:里面可以有多个条件,查询结果必须符合查询条件中的一个或多个。

  • must:里面的多个条件都必须成立

  • must_not:里面的多个条件必须不成立

// 书名必须包含Story的
GET /douban/book/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match":{
            "book_name":"Story"
          }
        }
      ]
    }
  }
}

// 书名必须不包含Story的
GET /douban/book/_search
{
  "query": {
    "bool": {
      "must_not": [
        {
          "match":{
            "book_name":"Story"
          }
        }
      ]
    }
  }
}

// 书名必须不包含Story,书名包含Adventures或Immortality的
GET /douban/book/_search
{
  "query": {
    "bool": {
      "must_not": [
        {
          "match":{
            "book_name":"Story"
          }
        }
      ],
      "should": [
        {
          "match": {
            "book_name": "Adventures"
          }
        },
        {
          "match": {
            "book_name": "Immortality"
          }
        }
      ]
    }
  }
}


// 在should、must、must_not这些里面都可以放多个条件
GET /douban/book/_search
{
  "query": {
    "bool": {
      "must_not": [
        {
          "match":{
            "book_name":"Story"
          }
        },
        {
          "match": {
            "book_name": "Adventures"
          }
        }
      ]
    }
  }
}

// 如果是单个条件的时候,还可以这样写,省去[]:
GET /douban/book/_search
{
  "query": {
    "bool": {
      "must_not": {
          "match":{
            "book_name":"Story"
          }
      }
    }
  }
}

// 还可以条件嵌套,也就是再嵌套一层bool,不过要注意逻辑,例如:
// 查询出(书名有story)或者(书名有The而且作者名有David)的,第二个是可成立可不成立的。
GET /douban/book/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "book_name": "Story"
          }
        },
        {
          "bool": {
            "must": [
              {
                "match": {
                  "book_name": "The"
                }
              },
              {
                "match": {
                  "book_author": "David"
                }
              }
            ]
          }
        }
      ]
    }
  }
}
  • 上面主要讲解了:
  • 基于bool、should、must、must_not的多条件搜索,上面的知识已经能基础地实现一些搜索功能了。
  • 索指定分词器、给多条件指定匹配数量、滚动查询还没了解

文档的过滤filter

过滤的效果其实有点像条件搜索,不过条件搜索会考虑相关度分数和考虑分词,而过滤是不考虑这些的,过滤对相关度没有影响。过滤一般用于结构化的数据上,也就是通常不用于使用了分词的数据上,通常都会用在数值类型和日期类型的数据上。

  • 例子
    // range,gte是不小于,lte是不大于,eq是等于,gt是大于,lt是小于
    GET / index/type/_search
    {
      "query": {
        "range": {
          "字段名": {
            "gte": 比较值
            [,"lte": 比较值]
          }
        }
      }
    }
    GET /douban/book/_search
    {
      "query": {
        "range": {
          "book_pages": {
            "gte": 352,
            "lt":400
          }
        }
      }
    }
    
    
    // term用于匹配字符串和数值型类型的数据(解决了range中没有eq的问题),但不能直接用于分词的字段。
    //【这个并没有那么简单,会后续再讲,直接匹配一些会分词的字段时,会匹配失败,
    //因为这时候这个字段拿来匹配的都是散乱的值,不是完整的原本的字段数据,所以下面用了不分词的数值型的字段来演示】
    GET /douban/book/_search
    {
      "query": {
        "term": {
          "字段": "搜索值"
        }
      }
    }
    GET /douban/book/_search
    {
      "query": {
        "term": {
          "book_pages": 352
        }
      }
    }
    
    
    //terms
    GET /douban/book/_search
    {
      "query": {
        "terms": {
          "字段": ["搜索值1","搜索值2"]
        }
      }
    }
    GET /douban/book/_search
    {
      "query": {
        "terms": {
          "book_pages": [
            "352",
            "400"
          ]
        }
      }
    }
    
  • filter与bool
GET /douban/book/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match":{
            "book_name":"Story"
          }
        },
        {
          "range": {
            "book_pages": {
              "lte":300
              }
          }
        }
      ]
    }
  }
}

GET /douban/book/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match":{
            "book_name":"Story"
          }
        },
        {
          "range": {
            "book_pages": {
              "lte":300
              }
          }
        },
        {
          "term": {
            "publish_date": "1994-02-01"
          }
        }
      ]
    }
  }
}
  • constant_score
GET /douban/book/_search
{
	"query": {
		"constant_score": {
			"filter": {
				"range": {
					"book_pages": {
						"gte": 352,
						"lt": 400
					}
				}
			}
		}
	}
}

// boost设置filter提供的相关度score值
GET /douban/book/_search
{
	"query": {
		"constant_score": {
			"filter": {
				"range": {
					"book_pages": {
						"gte": 352,
						"lt": 400
					}
				}
			},
			"boost": 1.2
		}
	}
}
  • 过滤通常用于过滤结构化数据,也就是那些不分词的数据,
  • 其中range用于数值范围过滤,term用于字符类型的数据或数值类型的数据的值是否相等
  • terms是term的复数版。过滤也支持bool拼接多个条件。
  • 过滤提供的相关度分数是一个常数,默认是1。

文档的聚合

mysql有聚合函数,es也可以聚合。

ElasticSearch中常见的聚合分析函数有terms(分组函数)、avg(平均数)、range(区间分组)、max(求最大值)、min(求最小值)、cardinality(获取唯一值的数量)、value_count(获取值的数量,不去重,可以得出多少个值参与了聚合)

  • 例子
    // 按性别分组
    GET /douban/book/_search
    {
      "aggs": {
        "groud_by_express": {
          "terms": {
            "field": "book_id",
            "size": 10
          }
        }
      }
    }
    //求年龄的平均数
    GET /people/test/_search
    {
      "aggs": {
        "avg_of_age": {
          "avg": {
            "field": "age"
          }
        }
      }
    }
    // 求年龄的最大值:
    GET /people/test/_search
    {
      "aggs": {
        "max_of_age": {
          "max": {
            "field": "age"
          }
        }
      }
    }
    // 把年龄[15,17]的分成一组,把年龄[18,25]的分成一组
    GET /people/test/_search
    {
      "aggs": {
        "range_by_age": {
          "range": {
            "field": "age",
            "ranges": [
              {
                "from": 15,
                "to": 17
              },
              {
                "from": 18,
                "to": 25
              }
            ]
          }
        }
      }
    }
    // 获取不同的年龄数:,比如有年龄[1,2,3,3,4,5],得到的结果是5,因为3只算一次
    GET /people/test/_search
    {
      "aggs": {
        "get_diff_age_count": {
          "cardinality": {
            "field": "age"
          }
        }
      }
    }
    

其他语法

  1. 先查询后聚合
    GET /people/test/_search
    {
      "query": {
        "match": {
          "name": "lilei1"
        }
      }, 
      "aggs": {
        "avg_of_age": {
          "avg": {
            "field": "age"
          }
        }
      }
    }
  2. 先过滤后聚合
    // 先获取年龄大于15的,再求平均值
    GET /people/test/_search
    {
      "query": {
        "range": {
          "age": {
            "gt":15
          }
        }
      }, 
      "aggs": {
        "avg_of_age": {
          "avg": {
            "field": "age"
          }
        }
      }
    }
  3. 聚合函数嵌套
    // 先按性别分组,再获取年龄平均值
    GET /people/test/_search
    {
    	"aggs": {
    		"groud_by_express": {
    			"terms": {
    				"field": "gender"
    			},
    			"aggs": {
    				"avg_of_age": {
    					"avg": {
    						"field": "age"
    					}
    				}
    			}
    		}
    	}
    }
  4. 聚合+排序
    // 先按性别分组,再按分组的年龄平均值降序排序,order中的avg_of_age就是下面的聚合函数的自定义名称
    GET /people/test/_search
    {
    	"aggs": {
    		"groud_by_express": {
    			"terms": {
    				"field": "gender",
    				"order": {
    				  "avg_of_age": "desc"
    				}
    			},
    			"aggs": {
    				"avg_of_age": {
    					"avg": {
    						"field": "age"
    					}
    				}
    			}
    		}
    	}
    }

aggs是与query同级的,使用聚合函数需要自己定义一个外层的聚合函数名称,
avg用于求平均值,max用于求最大值,range用于范围分组,term用于数据分组。
分组可以与条件搜索和过滤一起使用,aggs是与query同级的,聚合函数也可以嵌套使用。

文档的分页、排序

分页

// 从第一条开始,获取两条数据
GET /people/test/_search
{
  "from": 0,
  "size": 2
}

// 可以先查询,再分页
GET /people/test/_search
{
  "query": {
    "match": {
      "name": "lilei1"
    }
  }, 
  "from": 0,
  "size": 1
}

排序

排序处理:【sort与query同级别,是一个数组,里面可以有多个排序参数,参数以{"FIELD":{"order":"desc/asc"}}为格式】
GET /people/test/_search
{
  "query": {
    "match_all": {}
  }, 
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ]
}

这小结主要讲使用from和size分页,使用sort排序


Author: 向天歌
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source 向天歌 !
  TOC