国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Elasticsearch(十四)搜索---搜索匹配功能⑤--全文搜索

這篇具有很好參考價(jià)值的文章主要介紹了Elasticsearch(十四)搜索---搜索匹配功能⑤--全文搜索。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

一、前言

不同于之前的term。terms等結(jié)構(gòu)化查詢,全文搜索首先對(duì)查詢?cè)~進(jìn)行分析,然后根據(jù)查詢?cè)~的分詞結(jié)果構(gòu)建查詢。這里所說的全文指的是文本類型數(shù)據(jù)(text類型),默認(rèn)的數(shù)據(jù)形式是人類的自然語言,如對(duì)話內(nèi)容、圖書名稱、商品介紹和酒店名稱等。結(jié)構(gòu)化搜索關(guān)注的是數(shù)據(jù)是否匹配,全文搜索關(guān)注的是匹配程度;結(jié)構(gòu)化搜索一般用于精確匹配,而全文搜索用于部分匹配。本章將詳細(xì)介紹使用最多的全文搜索。

二、match查詢

match查詢是全文搜索的主要代表。對(duì)于最基本的match搜索來說,只要分詞中的一個(gè)或者多個(gè)在文檔中存在即可。例如搜索“京盛酒店”,查詢?cè)~先被分詞器切分為“京”“盛”“酒”“店”,因此,只要文檔中包含這4個(gè)字中的任何一個(gè)字,都會(huì)被搜索到。
您可能會(huì)有疑問,為什么“京盛酒店被切分為4個(gè)字而不是“京盛”“酒店”兩個(gè)詞呢?這是因?yàn)樵谀J(rèn)情況下,match查詢使用的是標(biāo)準(zhǔn)分詞器。該分詞器比較適用于英文,如果是中文則按照字進(jìn)行切分,因此默認(rèn)的分詞器不適合做中文搜索,在后面的章節(jié)中將介紹如何安裝和使用中文分詞器。
以下DSL示例為按照標(biāo)題搜索“京盛酒店”:

POST /hotel/_search
{
  "query": {
    "match": {   //匹配title字段為"金都酒店"的文檔
      "title":  "京盛酒店"
    }
  }
}

或者按照如下形式搜索:

POST /hotel/_search
{
  "query": {
    "match": {
      "title": {
        "query": "京盛酒店"
      }
    }
  }
}

搜索結(jié)果如下:

{
  ...
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 1.3428942,
    "hits" : [
      {
        "_index" : "hotel",
        "_type" : "_doc",
        "_id" : "002",
        "_score" : 1.3428942,
        "_source" : {
          "title" : "京盛酒店",
          "city" : "北京",
          "price" : "337.00",
          "create_time" : "2020-07-29 13:00:00",
          "amenities" : "充電停車場/可升降停車場",
          "full_room" : false,
          "location" : {
            "lat" : 39.911543,
            "lon" : 116.403
          },
          "praise" : 60
        }
      },
      {
        "_index" : "hotel",
        "_type" : "_doc",
        "_id" : "30",
        "_score" : 1.2387041,
        "_source" : {
          "title" : "京盛酒小店",
          "city" : "上海",
          "price" : "300.00",
          "create_time" : "2022-01-29 22:52:00",
          "amenities" : "露天游泳池,普通/充電停車場",
          "full_room" : false,
          "praise" : 2000
        }
      },
      {
        "_index" : "hotel",
        "_type" : "_doc",
        "_id" : "27",
        "_score" : 0.5495611,
        "_source" : {
          "title" : "盛況精選酒店",
          "city" : "南昌",
          "price" : "900.00",
          "create_time" : "2022-07-29 22:50:00",
          "amenities" : "露天游泳池,普通/充電停車場",
          "full_room" : false,
          "location" : {
            "lat" : 56.918229,
            "lon" : 126.422011
          },
          "praise" : 200
        }
      }
    ]
  }
}

從結(jié)果中可以看到,匹配度最高的文檔是002,該酒店的名稱和查詢?cè)~相同,得分為1.3428942;次之的文檔是30,因?yàn)樵摼频昝Q中包含“京”“盛”“酒”“店”。但是想比前一個(gè)文檔多了一個(gè)“小”字,所以部分匹配。再次之的文檔是27,它只有“盛”“酒”“店”三個(gè)字和查詢?cè)~部分匹配,因此排在最后。
假設(shè)用戶搜索名稱中同時(shí)包含“京”和“盛”的酒店,顯然之前最后一個(gè)文檔27就不是用戶想要命中的文檔。那么在ES中,match搜索可以設(shè)置operator參數(shù),該參數(shù)決定文檔按照分詞后的詞集合進(jìn)行“與”還是“或”匹配。在默認(rèn)情況下,該參數(shù)的值為“或”關(guān)系,即operator的值為or,這也解釋了搜索結(jié)果中包含部分匹配的文檔。如果希望各個(gè)詞之間的匹配結(jié)果是“與”關(guān)系,則可以設(shè)置operator參數(shù)的值為and。
下面的請(qǐng)求示例設(shè)置查詢?cè)~之間的匹配結(jié)果為“與”關(guān)系:

POST /hotel/_search
{
  "query": {
    "match": {
      "title": {
        "query": "京盛酒店",
        "operator": "and"
      }
    }
  }
}

搜索結(jié)果如下:

{
  ...
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.3428942,
    "hits" : [
      {
        "_index" : "hotel",
        "_type" : "_doc",
        "_id" : "002",
        "_score" : 1.3428942,
        "_source" : {
          "title" : "京盛酒店",
          "city" : "北京",
          "price" : "337.00",
          "create_time" : "2020-07-29 13:00:00",
          "amenities" : "充電停車場/可升降停車場",
          "full_room" : false,
          "location" : {
            "lat" : 39.911543,
            "lon" : 116.403
          },
          "praise" : 60
        }
      },
      {
        "_index" : "hotel",
        "_type" : "_doc",
        "_id" : "30",
        "_score" : 1.2387041,
        "_source" : {
          "title" : "京盛酒小店",
          "city" : "上海",
          "price" : "300.00",
          "create_time" : "2022-01-29 22:52:00",
          "amenities" : "露天游泳池,普通/充電停車場",
          "full_room" : false,
          "praise" : 2000
        }
      }
    ]
  }
}

有時(shí)搜索多個(gè)關(guān)鍵字,關(guān)鍵詞和文檔在某一個(gè)比例上匹配即可,如果使用“與”操作過于嚴(yán)苛,如果使用“或”操作又過于寬松。這時(shí)可以采用minimum_should_match參數(shù),該參數(shù)叫作最小匹配參數(shù),其值為一個(gè)數(shù)值,意義為可以匹配上的詞的個(gè)數(shù).在一般情況下將其設(shè)置為一個(gè)百分?jǐn)?shù),因?yàn)樵谡鎸?shí)場景中并不能精確控制具體的匹配數(shù)量。以下示例設(shè)置最小匹配為80%的文檔:

POST /hotel/_search
{
  "query": {
    "match": {
      "title": {
        "query": "京盛酒店",
        "operator": "or",
        "minimum_should_match": "80%"    //設(shè)置最小匹配度為80%
      }
    }
  }
}

這樣的話就需要滿足最后命中的文檔字?jǐn)?shù)占查詢條件中“京盛酒店”的80%(向下取整),例如這里4*80%,其實(shí)查詢結(jié)果只需要有條件中任意三個(gè)字符即可。
在Java客戶端上可以使用QueryBuilders.matchQuery()方法構(gòu)建match請(qǐng)求,分別給該方法傳入字段名稱和查詢值即可進(jìn)行match查詢。以下代碼展示了match請(qǐng)求的使用邏輯:
service層

	public List<Hotel> matchQuery(HotelDocRequest hotelDocRequest) throws IOException {
		//新建搜索請(qǐng)求
		String indexName = getNotNullIndexName(hotelDocRequest);
		SearchRequest searchRequest = new SearchRequest(indexName);
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		//查詢title且查詢值之間關(guān)系是or,并且最小匹配參數(shù)為80%
		MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder("title", hotelDocRequest.getTitle()).operator(Operator.OR).minimumShouldMatch("80%");
		searchSourceBuilder.query(matchQueryBuilder);
		searchRequest.source(searchSourceBuilder);
		return getQueryResult(searchRequest);
	}

controller層

	@PostMapping("/query/match")
	public FoundationResponse<List<Hotel>> matchQuery(@RequestBody HotelDocRequest hotelDocRequest) {
		try {
			List<Hotel> hotelList = esQueryService.matchQuery(hotelDocRequest);
			if (CollUtil.isNotEmpty(hotelList)) {
				return FoundationResponse.success(hotelList);
			} else {
				return FoundationResponse.error(100,"no data");
			}
		} catch (IOException e) {
			log.warn("搜索發(fā)生異常,原因?yàn)?{}", e.getMessage());
			return FoundationResponse.error(100, e.getMessage());
		} catch (Exception e) {
			log.error("服務(wù)發(fā)生異常,原因?yàn)?{}", e.getMessage());
			return FoundationResponse.error(100, e.getMessage());
		}
	}

postman調(diào)用截圖
Elasticsearch(十四)搜索---搜索匹配功能⑤--全文搜索,elasticsearch,大數(shù)據(jù),搜索引擎,java

三、multi_match查詢

有時(shí)用戶需要在多個(gè)字段中查詢關(guān)鍵詞,除了使用布爾查詢封裝多個(gè)match查詢之外,可替代的方案是使用multi_match。可以在multi_match的query子句中組織數(shù)據(jù)匹配規(guī)則,并在fields子句中指定需要搜索的字段列表。
下面的示例在title和amenities兩個(gè)字段中同時(shí)搜索“假日”關(guān)鍵詞:

POST /hotel/_search
{
  "query": {
    "multi_match": {
      "query": "假日",
      "fields": [
        "amenities",
        "title"
        ]
    }
  }
}

搜索結(jié)果如下:

{
  "took" : 14,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 4,
      "relation" : "eq"
    },
    "max_score" : 4.2939954,
    "hits" : [
      {
        "_index" : "hotel",
        "_type" : "_doc",
        "_id" : "28",
        "_score" : 4.2939954,
        "_source" : {
          "title" : "京盛假日酒店",
          "city" : "上海",
          "price" : "600.00",
          "create_time" : "2021-04-29 22:52:00",
          "amenities" : "露天游泳池,普通/充電停車場",
          "full_room" : false,
          "praise" : 200
        }
      },
      {
        "_index" : "hotel",
        "_type" : "_doc",
        "_id" : "003",
        "_score" : 1.9696801,
        "_source" : {
          "title" : "文雅文化酒店",
          "city" : "天津",
          "price" : "260.00",
          "create_time" : "2021-02-27 22:00:00",
          "amenities" : "提供假日party,免費(fèi)早餐,浴池,充電停車場",
          "full_room" : true,
          "location" : {
            "lat" : 39.186555,
            "lon" : 117.162767
          },
          "praise" : 30
        }
      },
      {
        "_index" : "hotel",
        "_type" : "_doc",
        "_id" : "29",
        "_score" : 1.9163029,
        "_source" : {
          "title" : "京盛欣欣酒店",
          "city" : "上海",
          "price" : "700.00",
          "create_time" : "2022-01-29 22:52:00",
          "amenities" : "提供假日party,露天游泳池,普通/充電停車場",
          "full_room" : false,
          "praise" : 200
        }
      },
      {
        "_index" : "hotel",
        "_type" : "_doc",
        "_id" : "004",
        "_score" : 1.6876338,
        "_source" : {
          "title" : "京盛集團(tuán)酒店",
          "city" : "上海",
          "price" : "800.00",
          "create_time" : "2021-05-29 21:35:00",
          "amenities" : "浴池(假日需預(yù)訂),室內(nèi)游泳池,普通停車場/充電停車場",
          "full_room" : true,
          "location" : {
            "lat" : 36.940243,
            "lon" : 120.394
          },
          "praise" : 100
        }
      }
    ]
  }
}

根據(jù)結(jié)果可以看到,命中的文檔要么在title中包含“假日”關(guān)鍵詞,要么在amenities字段中包含“假日”關(guān)鍵詞。
且之前在Match搜索講到的operator,minimum_should_match等參數(shù)在multi_match搜索中同樣適用。
在Java客戶端上可以使用QueryBuilders.multiMatchQuery()方法或者直接new MultiMatchQueryBuilder()構(gòu)建multi_match請(qǐng)求
可以看到,我們構(gòu)造MultiMatchQueryBuilder,除了查詢值,字段它接收的是一個(gè)可變長String數(shù)組
Elasticsearch(十四)搜索---搜索匹配功能⑤--全文搜索,elasticsearch,大數(shù)據(jù),搜索引擎,java
所以我們可以在傳參hotelDocRequest加兩個(gè)參數(shù),一個(gè)是multiQueryValue代表要查詢的值,另一個(gè)是multiQueryPropertyNames代表想要在哪些字段查詢
分別給該方法傳入查詢值和多個(gè)字段名稱即可進(jìn)行multi_match查詢。以下代碼展示了multi_match請(qǐng)求的使用邏輯:
Service層
由于上面講到構(gòu)造MultiMatchQueryBuilder接收的是可變長String數(shù)組,所以我們要對(duì)傳參的List通過list.stream().toArray(String[]::new);轉(zhuǎn)化為String可變長數(shù)組(String…等價(jià)于String[])。

	public List<Hotel> multiMatchQuery(HotelDocRequest hotelDocRequest) throws IOException {
		//新建搜索請(qǐng)求
		String indexName = getNotNullIndexName(hotelDocRequest);
		SearchRequest searchRequest = new SearchRequest(indexName);
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		MultiMatchQueryBuilder multiMatchQueryBuilder = new MultiMatchQueryBuilder(hotelDocRequest.getMultiQueryValue(), hotelDocRequest.getMultiQueryPropertyNames().toArray(new String[0]));
		searchSourceBuilder.query(multiMatchQueryBuilder);
		searchRequest.source(searchSourceBuilder);
		return getQueryResult(searchRequest);
	}

controller層

	@PostMapping("/query/multiMatch")
	public FoundationResponse<List<Hotel>> multiMatchQuery(@RequestBody HotelDocRequest hotelDocRequest) {
		try {
			List<Hotel> hotelList = esQueryService.multiMatchQuery(hotelDocRequest);
			if (CollUtil.isNotEmpty(hotelList)) {
				return FoundationResponse.success(hotelList);
			} else {
				return FoundationResponse.error(100,"no data");
			}
		} catch (IOException e) {
			log.warn("搜索發(fā)生異常,原因?yàn)?{}", e.getMessage());
			return FoundationResponse.error(100, e.getMessage());
		} catch (Exception e) {
			log.error("服務(wù)發(fā)生異常,原因?yàn)?{}", e.getMessage());
			return FoundationResponse.error(100, e.getMessage());
		}
	}

postman運(yùn)行截圖
Elasticsearch(十四)搜索---搜索匹配功能⑤--全文搜索,elasticsearch,大數(shù)據(jù),搜索引擎,java

四、match_phrase查詢

match_phrase用于匹配短語,與match查詢不同的是,match_phrase用于搜索確切的短語或臨近的詞語。假設(shè)在酒店標(biāo)題中搜索“京盛酒店”,希望酒店標(biāo)題中的“京盛酒店”四字完全按照搜索詞的順序并且緊鄰,此時(shí)就需要使用match_phrase查詢:

POST /hotel/_search
{
  "query": {
    "match_phrase": {
      "title": {
        "query": "京盛酒店"
      }
    }
  }
}

結(jié)果如下:

{
  ...
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.3428942,
    "hits" : [
      {
        "_index" : "hotel",
        "_type" : "_doc",
        "_id" : "002",
        "_score" : 1.3428942,
        "_source" : {
          "title" : "京盛酒店",
          "city" : "北京",
          "price" : "337.00",
          "create_time" : "2020-07-29 13:00:00",
          "amenities" : "充電停車場/可升降停車場",
          "full_room" : false,
          "location" : {
            "lat" : 39.911543,
            "lon" : 116.403
          },
          "praise" : 60
        }
      }
    ]
  }
}

根據(jù)上述結(jié)果可知,使用match_phrase查詢后,只有文檔002命中,而類似之前的“京盛集團(tuán)酒店”等類似文檔沒有被命中,這是為什么呢?
我們知道,在默認(rèn)標(biāo)準(zhǔn)分詞器的情況下,文檔002的title字段被切分為“京”“盛”“酒”“店”,其中這些分詞后的文檔下標(biāo)“京”代表0,盛”代表1,“酒”代表2,“店”代表3,而對(duì)于match_phrase查詢,在不去設(shè)置下標(biāo)移動(dòng)步長的情況下這些分詞文檔想要移動(dòng)到理想位置(查詢?cè)~的位置,這里就是京盛酒店)的步數(shù)默認(rèn)就是0,而可以發(fā)現(xiàn),我們命中的文檔002“京盛酒店”,這個(gè)文檔下標(biāo)其實(shí)就已經(jīng)是理想位置了,不需要額外移動(dòng),相當(dāng)于步長就是0,所以能夠命中。而對(duì)于“京盛集團(tuán)酒店”,分詞后“盛”想要移動(dòng)到“酒”這個(gè)下標(biāo),需要移動(dòng)2次,所以步長是2,不符合默認(rèn)的步長,所以無法命中。
那么如果需要“京盛集團(tuán)酒店”也能夠被命中,則可以設(shè)置match_phrase查詢的slop參數(shù),它用來調(diào)節(jié)匹配詞之間的距離閾值,即上面說的步長,下面的DSL將slop設(shè)置為2

POST /hotel/_search
{
  "query": {
    "match_phrase": {
      "title": {
        "query": "京盛酒店",
        "slop":2
      }
    }
  }
}

可以看到這樣就能命中“京盛集團(tuán)酒店”了
Elasticsearch(十四)搜索---搜索匹配功能⑤--全文搜索,elasticsearch,大數(shù)據(jù),搜索引擎,java
在Java客戶端上可以使用QueryBuilders.matchPhraseQuery()方法構(gòu)建match_phrase請(qǐng)求,分別給該方法傳入查詢字段和值即可運(yùn)行multi_match查詢。這一點(diǎn)和match搜索很像。以下代碼展示了match_phrase請(qǐng)求的使用邏輯:
Service層

	public List<Hotel> matchPhraseQuery(HotelDocRequest hotelDocRequest) throws IOException {
		//新建搜索請(qǐng)求
		String indexName = getNotNullIndexName(hotelDocRequest);
		SearchRequest searchRequest = new SearchRequest(indexName);
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		//構(gòu)造MatchPhraseQueryBuilder且設(shè)置步長為2
		MatchPhraseQueryBuilder matchPhraseQueryBuilder = new MatchPhraseQueryBuilder("title", hotelDocRequest.getTitle()).slop(2);
		searchSourceBuilder.query(matchPhraseQueryBuilder);
		searchRequest.source(searchSourceBuilder);
		return getQueryResult(searchRequest);
	}

Controller層

	@PostMapping("/query/matchPhrase")
	public FoundationResponse<List<Hotel>> matchPhraseQuery(@RequestBody HotelDocRequest hotelDocRequest) {
		try {
			List<Hotel> hotelList = esQueryService.matchPhraseQuery(hotelDocRequest);
			if (CollUtil.isNotEmpty(hotelList)) {
				return FoundationResponse.success(hotelList);
			} else {
				return FoundationResponse.error(100,"no data");
			}
		} catch (IOException e) {
			log.warn("搜索發(fā)生異常,原因?yàn)?{}", e.getMessage());
			return FoundationResponse.error(100, e.getMessage());
		} catch (Exception e) {
			log.error("服務(wù)發(fā)生異常,原因?yàn)?{}", e.getMessage());
			return FoundationResponse.error(100, e.getMessage());
		}
	}

Postman運(yùn)行截圖:
Elasticsearch(十四)搜索---搜索匹配功能⑤--全文搜索,elasticsearch,大數(shù)據(jù),搜索引擎,java文章來源地址http://www.zghlxwxcb.cn/news/detail-667099.html

到了這里,關(guān)于Elasticsearch(十四)搜索---搜索匹配功能⑤--全文搜索的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包