match_all
match_querymulti_match_queryidsrangetermgeo_distancegeo_bounding_boxboolfunction_score常见的全文检索查询包括
match查询:单字段查询multi_match查询:多字段查询,任意一个字段符合条件就算符合查询条件match查询语法如下所示
GET /indexName/_search
{
"query": {
"match":{
"FIELD": "TEXT"
}
}
}
match_all查询语法如下
GET /indexName/_search
{
"query": {
"multi_match": {
"query": "TEXT",
"fileds": ["FILED1", "FILED2"]
}
}
}
比如要搜索name字段中存在 如家酒店,DSL语句如下所示
GET hotel/_search
{
"query": {
"match": {
"name": "如家酒店"
}
},
"size": 2 # size的意思是只显示n条数据
}
搜索结果如下所示

结果分析
因为name字段是类型是text,搜索的时候会对这个字段进行分词
如搜索如家酒店,那么就会分词称为如家,酒店,相当于会搜索三次,并取这三次搜索的并集(ES默认的是并集),所以搜索的命中率才会如此之高
name like %如家%算一条数据,搜索到酒店也算一条数据name like %如家酒店%才能算是一条数据那么如何取交集呢?,如下所示
DSL
# 取交集,并集是or
GET hotel/_search
{
"query": {
"match": {
"name": {
"query": "如家酒店",
"operator": "and"
}
}
}
}
运行结果

代码如下所示
package com.coolman.hotel.test;
import com.coolman.hotel.pojo.HotelDoc;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.IOException;
@SpringBootTest
public class FullTextSearchDemo {
// 注入 RestHighLevelClient对象
@Autowired
private RestHighLevelClient restHighLevelClient;
// jackson
private final ObjectMapper objectMapper = new ObjectMapper();
/**
* 查询所有测试
*/
@Test
public void testMatchAll() throws IOException {
// 1. 创建一个查询请求对象
SearchRequest searchRequest = new SearchRequest("hotel"); // 指定索引
// 2. 添加查询的类型
MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
searchRequest.source().query(matchAllQueryBuilder); // source就相当于{}
searchRequest.source().size(100); // RestAPI默认返回的是10条数据,可以更改size的属性,即可自定义返回的数据量
// 3. 发出查询的请求,得到响应结果
SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 4. 处理响应的结果
handlerResponse(response);
}
/**
* 用来处理响应数据(相当于解析返回的JSON数据)
* @param response
*/
private void handlerResponse(SearchResponse response) throws JsonProcessingException {
// 1. 得到命中的数量(即总记录数量)
SearchHits hits = response.getHits();
long totalCount = hits.getTotalHits().value;// 总记录数
System.out.println("总记录数量为:" + totalCount);
// 2. 获取本次查询出来的列表数据
SearchHit[] hitsArray = hits.getHits();
for (SearchHit hit : hitsArray) {
// 得到json字符串
String json = hit.getSourceAsString();
// 将json字符串转换为实体类对象
HotelDoc hotelDoc = objectMapper.readValue(json, HotelDoc.class);
System.out.println(hotelDoc);
}
}
}
~~~
代码如下所示
/**
* 单字段查询
*/
@Test
public void testMatch() throws IOException {
// 1. 创建查询请求对象
SearchRequest searchRequest = new SearchRequest("hotel");
// 2. 添加查询的类型
MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name", "如家酒店");
searchRequest.source().query(matchQueryBuilder);
// 3. 发出查询请求,得到响应数据
SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 4. 处理响应的结果
handlerResponse(response);
}
自行运行查看结果即可
比如搜索name和brand字段中出现如家酒店的数据
DSL语句如下所示
GET hotel/_search
{
"query": {
"multi_match": {
"query": "如家酒店",
"fields": ["name", "brand"]
}
}
}
运行结果如下所示

不过多字段查询的使用很少,因为多字段查询会使得查询效率变慢
一般都会在创建映射的时候,使用copy_to将指定字段的值拷贝到另一个字段,如自定义的all字段
这样子就可以使用单字段查询,提高查询效率
跟单字段查询差不多,只不过使用QueryBuilders创建的对象略有不同罢了
代码如下所示
/**
* 多字段查询
*/
@Test
public void testMultiMatch() throws IOException {
// 1. 创建查询请求球体对象
SearchRequest searchRequest = new SearchRequest("hotel");
// 2. 添加要查询的字段
// MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("如家酒店", "name", "brand", "bussiness");
// searchRequest.source().query(multiMatchQueryBuilder);
// 因为在创建映射的时候使用了copy_to,索引上面的多字段查询等价于下面的单字段查询
MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("all", "如家酒店");
searchRequest.source().query(matchQueryBuilder);
// 3. 执行查询操作,得到响应对象
SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 4. 处理响应对象
handlerResponse(response);
}
keyword、数值、日期、boolean等类型的字段,所以不会对搜索条件分词,常见的有如下
term
equals、=range
>=、<=、between、andterm查询因为精确查询的字段搜索的是不分词的字段,因此查询的条件也必须是不分词的词条
查询的时候,用户输入的内容跟自动值完全匹配的时候才认为符合条件
如果用户输入的内容过多,反而搜索不到数据
语法说明
# term 精确查询
GET /indexName/_search
{
"query": {
"term": {
"FILED": {
"value": "VALUE"
}
}
}
}
示例


range查询范围查询,一般应用在对数值类型做范围过滤的时候。比如做价格范围过滤
基本语法
# range 精确查询
# gte表示大于等于;gt表示大于
# lte表示小于等于;lt表示小于
GET /indexName/_search
{
"query": {
"range": {
"FIELD": {
"gte": 10,
"lte": 20
}
}
}
}
示例
price大于等于200,小于等于500的酒店
term查询
代码如下所示
/**
* term 精确查询
*/
@Test
public void testTermQuery() throws IOException {
// 1. 创建查询请求对象
SearchRequest searchRequest = new SearchRequest("hotel");
// 2. 添加要查询的字段
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("brand", "如家");
searchRequest.source().query(termQueryBuilder);
// 3. 发出查询的请求,获取响应结果
SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 4. 处理响应的结果
handlerResponse(response);
}
range查询
代码如下所示
/**
* range 精确查询
*/
@Test
public void testRangeQuery() throws IOException {
// 1. 创建查询请求对象
SearchRequest searchRequest = new SearchRequest("hotel");
// 2. 添加查询的字段
RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("price");
rangeQuery.gte(300); // 大于等于300
rangeQuery.lte(500); // 小于等于500
searchRequest.source().query(rangeQuery);
// 3. 执行查询操作,获取响应结果
SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 4. 处理响应结果
handlerResponse(response);
}
矩形范围查询,也就是geo_bounding_box查询,查询坐标落在某个矩形范围的所有文档
查询的时候,需要指定矩形的左上、右下两个点的坐标,然后画出一个矩形,落在该矩形内的都是符合条件的点,如下所示

语法如下所示
# 地理位置查询(矩形查询)
GET hotel/_search
{
"query": {
"geo_bounding_box": {
"location": {
"top_left": {
"lat": 31.1,
"lon": 121.5
},
"bottom_right": {
"lat": 30.9,
"lon": 121.7
}
}
}
}
}
示例

附近查询,也叫做距离查询(geo_distance)
换句话来说,在地图上找一个点作为圆心,以指定距离为半径,画一个圆,落在圆内的坐标都算符合条件,如下所示

语法如下所示
GET hotel/_search
{
"query": {
"geo_distance": {
"distance": "15km",
"location": "31.21,121.5"
}
}
}
示例

代码如下所示
/**
* 地理坐标矩形查询
*/
@Test
public void testGeoBoundingBoxSearch() throws IOException {
// 1. 创建查询请求对象
SearchRequest searchRequest = new SearchRequest("hotel");
// 2. 添加要查询的字段
// 指定要查询的字段为 location
GeoBoundingBoxQueryBuilder geoBoundingBoxQueryBuilder = QueryBuilders.geoBoundingBoxQuery("location");
// 指定 topLeft的坐标
geoBoundingBoxQueryBuilder.topLeft().resetLat(31.1);
geoBoundingBoxQueryBuilder.topLeft().resetLon(121.5);
// 指定 bottom_right的坐标
geoBoundingBoxQueryBuilder.bottomRight().resetLat(30.9);
geoBoundingBoxQueryBuilder.bottomRight().resetLon(121.7);
searchRequest.source().query(geoBoundingBoxQueryBuilder);
// 3. 发起请求
SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 4. 处理返回的数据
handlerResponse(response);
}
代码如下所示
/**
* 地理坐标附近查询(圆形)
*/
@Test
public void testGeoDistanceSearch() throws IOException {
// 1. 创建查询请求对象
SearchRequest searchRequest = new SearchRequest("hotel");
// 2. 添加要查询的字段
// 指定要查询的字段是 location
GeoDistanceQueryBuilder geoDistanceQueryBuilder = QueryBuilders.geoDistanceQuery("location");
// 指定中心点坐标
geoDistanceQueryBuilder.point(new GeoPoint(31.21, 121.5));
// 指定要查询的范围距离
geoDistanceQueryBuilder.distance("15km");
searchRequest.source().query(geoDistanceQueryBuilder);
// 3. 发起查询请求
SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 4. 处理返回的数据
handlerResponse(response);
}
must:必须匹配每个子查询,类似"与"(and),must的条件参与算分should:选择性匹配子查询,类似"或"(or)must_not:必须不匹配,不参与算分,类似"非"(not)filter:效果和must一样,都是and。必须匹配,filter的条件不参与算分
must查询,参与算分filter查询,不参与算分DSL语句如下所示
GET hotel/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"city": {
"value": "上海"
}
}
}
],
"should": [
{
"term": {
"brand": {
"value": "皇冠假日"
}
}
},
{
"term": {
"brand": {
"value": "华美达"
}
}
}
],
"must_not": [
{
"range": {
"price": {
"lte": 500
}
}
}
],
"filter": {
"range": {
"score": {
"gte": 45
}
}
}
}
}
}
这个DSL语句的意思通俗来说就是
示例
需求如下所示
分析
range过滤查询,不参与算分(可以放到must_not中,当然也可以放到filter中,使用lte表示小于等于400)geo_distance查询,属于过滤条件,不参与算分,放到filter中DSL语句如下所示
GET hotel/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "如家酒店"
}
}
],
"must_not": [
{
"range": {
"price": {
"gt": 400
}
}
}
],
"filter": {
"geo_distance": {
"distance": "10km",
"location": {
"lat": 31.21,
"lon": 121.5
}
}
}
}
}
}
PS:在kibana中编写filter中的坐标信息的时候自动补全有些bug,kibana会报错distacne_unit和location不能共存,所以应该把这个单位删除,然后在distance字段上添加双引号的同时带上单位
代码如下所示
/**
* 复合查询之布尔查询
*/
@Test
public void testBooleanQuery() throws IOException {
// 1. 创建查询请求对象
SearchRequest searchRequest = new SearchRequest("hotel");
// 2. 添加要查询的字段
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
// must
MatchQueryBuilder brand = QueryBuilders.matchQuery("name", "如家酒店");
boolQueryBuilder.must(brand);
// must_not
RangeQueryBuilder price = QueryBuilders.rangeQuery("price").gt(400);
boolQueryBuilder.mustNot(price);
// filter
GeoDistanceQueryBuilder location = QueryBuilders.geoDistanceQuery("location").point(new GeoPoint(31.21, 121.5)).distance("10km");
boolQueryBuilder.filter(location);
searchRequest.source().query(boolQueryBuilder);
// 3. 执行查询,得到响应数据
SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 4. 处理响应数据
handlerResponse(response);
}
match查询的时候,文档结果会根据搜索词条的关联度打分(_score),返回结果时按照分值降序排序




weight:函数结果是常量field_value_factor:以文档中的某个字段值作为函数结果random_score:以随机数作为函数结果script_score:自定义算分函数算法multiply:相乘replace:用function score替换query scoresum、avg、max、min让"如家"这个品牌的酒店排名靠前一点
这个需求很简单,可以理解为如下几部分
brand = "如家"weight给固定的算分结果因此DSL语句如下所示
GET hotel/_search
{
"query": {
"function_score": {
"query": {
"match": {
"name": "酒店"
}
},
"functions": [
{
"filter": {
"term": {
"brand": "如家"
}
},
"weight": 10
}
],
"boost_mode": "sum"
}
}
}
结果如下所示

原始搜索结果如下所示

代码如下所示,可以对照着DSL语句进行编写
/**
* 复合查询之算分函数查询
*/
@Test
public void testFunctionScoreQuery() throws IOException {
// 1. 创建查询请求对象
SearchRequest searchRequest = new SearchRequest("hotel");
// 2. 添加查询的请求体
searchRequest.source().query( // query
QueryBuilders.functionScoreQuery( // function_score
QueryBuilders.matchQuery("name", "酒店"), // match
new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{ // functions
new FunctionScoreQueryBuilder.FilterFunctionBuilder( // filter
QueryBuilders.termQuery("brand", "如家"), // term
ScoreFunctionBuilders.weightFactorFunction(10) // weight
)
}
).boostMode(CombineFunction.SUM) // boost_mode
);
// 3. 执行查询,获取响应数据
SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 4. 处理响应数据
handlerResponse(response);
}
我使用Nokogiri(Rubygem)css搜索寻找某些在我的html里面。看起来Nokogiri的css搜索不喜欢正则表达式。我想切换到Nokogiri的xpath搜索,因为这似乎支持搜索字符串中的正则表达式。如何在xpath搜索中实现下面提到的(伪)css搜索?require'rubygems'require'nokogiri'value=Nokogiri::HTML.parse(ABBlaCD3"HTML_END#my_blockisgivenmy_bl="1"#my_eqcorrespondstothisregexmy_eq="\/[0-9]+\/"#FIXMEThefoll
寻找有用的ruby的好网站是什么? 最佳答案 AgileWebDevelopment列出插件(虽然不是rubygems,我不确定为什么),并允许人们对它们进行评级。RubyToolbox按类别列出gem并比较它们的受欢迎程度。Rubygems有一个搜索框。StackOverflow对最有用的rails插件和rubygems有疑问。 关于ruby-如何搜索有用的ruby,我们在StackOverflow上找到一个类似的问题: https://stacko
我有很多这样的文档:foo_1foo_2foo_3bar_1foo_4...我想通过获取foo_[X]的所有实例并将它们中的每一个替换为foo_[X+1]来转换它们。在这个例子中:foo_2foo_3foo_4bar_1foo_5...我可以用gsub和一个block来做到这一点吗?如果不是,最干净的方法是什么?我真的在寻找一个优雅的解决方案,因为我总是可以暴力破解它,但我觉得有一些正则表达式技巧值得学习。 最佳答案 我(完全)不懂Ruby,但类似这样的东西应该可以工作:"foo_1foo_2".gsub(/(foo_)(\d+)/
我读了"BingSearchAPI-QuickStart"但我不知道如何在Ruby中发出这个http请求(Weary)如何在Ruby中翻译“Stream_context_create()”?这是什么意思?"BingSearchAPI-QuickStart"我想使用RubySDK,但我发现那些已被弃用前(Rbing)https://github.com/mikedemers/rbing您知道Bing搜索API的最新包装器(仅限Web的结果)吗? 最佳答案 好吧,经过一个小时的挫折,我想出了一个办法来做到这一点。这段代码很糟糕,因为它是
给定一个元素和一个数组,Ruby#index方法返回元素在数组中的位置。我使用二进制搜索实现了我自己的索引方法,期望我的方法会优于内置方法。令我惊讶的是,内置的在实验中的运行速度大约是我的三倍。有Rubyist知道原因吗? 最佳答案 内置#indexisnotabinarysearch,这只是一个简单的迭代搜索。但是,它是用C而不是Ruby实现的,因此自然可以快几个数量级。 关于Ruby#index方法VS二进制搜索,我们在StackOverflow上找到一个类似的问题:
不知何故,我似乎无法获得包含我的聚合的响应...使用curl它按预期工作:HBZUMB01$curl-XPOST"http://localhost:9200/contents/_search"-d'{"size":0,"aggs":{"sport_count":{"value_count":{"field":"dwid"}}}}'我收到回复:{"took":4,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":90,"max_score":0.0,"hits":[]},"a
我有一个表,'jobs'和一个枚举字段'status'。status具有以下枚举集:enumstatus:[:draft,:active,:archived]使用ransack,我如何过滤表,比如说,所有事件记录? 最佳答案 你可以像这样在模型中声明自己的掠夺者:ransacker:status,formatter:proc{|v|statuses[v]}do|parent|parent.table[:status]end然后您可以使用默认的搜索语法_eq来检查相等性,如下所示:Model.ransack(status_eq:'ac
我一直在使用postgres关注railscast的全文搜索,但我不断收到以下错误#的未定义局部变量或方法“作用域”我关注了railscast确切地。我安装了所有正确的gem。(pg_search,pg)。这是我的代码文章Controller(我在这里也使用acts_as_taggable)defindex@articles=Article.text_search(params[:query]).page(params[:page]).per_page(3)ifparams[:tag]@articles=Article.tagged_with(params[:tag])else@art
我想使用部分字符串搜索数组,然后获取找到该字符串的索引。例如:a=["Thisisline1","Wehaveline2here","andfinallyline3","potato"]a.index("potato")#thisreturns3a.index("Wehave")#thisreturnsnil使用a.grep将返回完整的字符串,使用a.any?将返回正确的true/false语句,但都不会返回匹配的索引找到了,或者至少我不知道该怎么做。我正在编写一段代码,该代码读取文件、查找特定header,然后返回该header的索引,以便它可以将其用作future搜索的偏移量。如果
1.回顾.TransportServicepublicclassTransportServiceextendsAbstractLifecycleComponentTransportService:方法:1publicfinalTextendsTransportResponse>voidsendRequest(finalTransport.Connectionconnection,finalStringaction,finalTransportRequestrequest,finalTransportRequestOptionsoptions,TransportResponseHandlerT>