Java利用ElasticSearch實(shí)現(xiàn)自動(dòng)補(bǔ)全功能
前言
最近在學(xué)習(xí)elasticsearch,想實(shí)現(xiàn)跟谷歌和百度類(lèi)似的功能:下拉補(bǔ)全提示,如圖所示:
準(zhǔn)備
我使用的版本和依賴(lài)包,如下所示:
<properties> <java.version>17</java.version> <spring-boot.version>3.0.2</spring-boot.version> <spring-cloud.version>2022.0.0</spring-cloud.version> <spring-cloud-alibaba.version>2022.0.0.0-RC2</spring-cloud-alibaba.version> </properties> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> <dependency> <groupId>co.elastic.clients</groupId> <artifactId>elasticsearch-java</artifactId> <version>8.7.1</version> </dependency>
devtools操作
首先,我們必須先創(chuàng)建index
并設(shè)置成想要設(shè)置成下拉補(bǔ)全提示的字段為completion
類(lèi)型,如下所示:
PUT index_urls { "mappings": { "properties": { "suggest": { "type": "completion", "analyzer": "ik_smart" } } } }
這樣我們創(chuàng)建了index_urls
,并且設(shè)置好了suggest
字段是completion
類(lèi)型。
接著,我們往里面加點(diǎn)數(shù)據(jù),并且使用completion suggester
進(jìn)行查詢(xún),如下所示 :
// 自動(dòng)補(bǔ)全查詢(xún) GET /index_urls/_search { "suggest": { "title_suggest": { "text": "n", // 關(guān)鍵字 "completion": { "field": "suggest", // 補(bǔ)全查詢(xún)的字段 "skip_duplicates": true, // 跳過(guò)重復(fù)的 "size": 10 // 獲取前10條結(jié)果 } } } }
查詢(xún)結(jié)果如下所示:
{ "took": 1, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 0, "relation": "eq" }, "max_score": null, "hits": [] }, "suggest": { "title_suggest": [ { "text": "n", "offset": 0, "length": 1, "options": [ { "text": "npm、yarn的安裝和設(shè)置淘寶鏡像源_yarn設(shè)置淘寶鏡像_cn_ljr的博客-CSDN博客", "_index": "index_urls", "_id": "64d0548bd8239d21cb9fe4e5", "_score": 1, "_source": { "_class": "com.seaurl.searchservice.document.UrlIndex", "id": "64d0548bd8239d21cb9fe4e5", "uid": "6461e6ac25d966329b7d7642", "categoryId": "64b89acfaf50e77e53ef89ef", "categoryName": "戶(hù)外運(yùn)動(dòng)", "categoryParentId": "", "categoryParentName": "", "title": "npm、yarn的安裝和設(shè)置淘寶鏡像源_yarn設(shè)置淘寶鏡像_cn_ljr的博客-CSDN博客", "suggest": { "input": [ "npm、yarn的安裝和設(shè)置淘寶鏡像源_yarn設(shè)置淘寶鏡像_cn_ljr的博客-CSDN博客" ] }, "url": "https://blog.csdn.net/cn_ljr/article/details/126319130", "domain": "blog.csdn.net", "description": "安裝npm和yarn,配置npm和yarn的鏡像源為淘寶鏡像源_yarn設(shè)置淘寶鏡像", "favicon": "https://cdn.seaurl.com/space/url/blog.csdn.net/favicon.ico", "env": "dev", "createdDt": 1691374731421, "updatedDt": 1691374731421 } } ] } ] } }
這樣就完成了自動(dòng)補(bǔ)全提示查詢(xún)了,接下來(lái)我們使用java再實(shí)現(xiàn)一遍。
java操作
首先,我們創(chuàng)建實(shí)體類(lèi),并且定義completion
類(lèi)型的字段,如下所示:
@Data public class UrlIndex { private String id; private String uid; // 分類(lèi)id private String categoryId; private String categoryName; private String categoryParentId; private String categoryParentName; private String title; // 下拉提示建議使用的字段,注意:Completion類(lèi)型字段,不能做篩選用 // @CompletionField(analyzer="ik_smart",searchAnalyzer="ik_smart", maxInputLength = 100) private Completion suggest; private String url; private String domain; private String description; //如果沒(méi)獲取前端顯示domain首字母 private String favicon; private Date createdDt;//創(chuàng)建時(shí)間 private Date updatedDt;//更新時(shí)間 }
接著,我們往es中添加數(shù)據(jù),并且把查詢(xún)轉(zhuǎn)化成java代碼,如下所示:
private SearchResponse getEsSuggestionData(String filedName, String fieldValue) { try { String index = getEsIndexByEnv(); Suggester suggester = Suggester.of(s -> s .suggesters("title-suggest", FieldSuggester.of(fs -> fs .completion(cs -> cs.skipDuplicates(true) .size(10) .field(filedName) ) )) .text(fieldValue) ); return elasticsearchClient.search(s -> s.index(index) // 使用source可以返回固定字段 // .source() .suggest(suggester) , Map.class); } catch (Exception ex) { log.info("getEsSuggestionData error={}", ex.getMessage()); return null; } }
這樣就完成了查詢(xún)的功能,接下來(lái),我們要把返回的數(shù)據(jù)拿出來(lái),并轉(zhuǎn)換之后返回給前端顯示,如下所示:
@Override public List<UrlIndexDto> searchSuggestionDataBy(String fieldName, String fieldValue) { SearchResponse response = getEsSuggestionData(fieldName, fieldValue); if (response != null) { Map suggestMap = response.suggest(); if (suggestMap != null) { List<?> titleSuggestionList = (List<?>) suggestMap.get("title-suggest"); if (titleSuggestionList != null) { for (Object titleSuggestion : titleSuggestionList) { if (titleSuggestion instanceof Suggestion) { Suggestion suggestion = (Suggestion) titleSuggestion; if (suggestion.isCompletion()) { CompletionSuggest completionSuggest = suggestion.completion(); List<co.elastic.clients.elasticsearch.core.search.CompletionSuggestOption> options = completionSuggest.options(); List<UrlIndexDto> urlIndexDtos = new ArrayList<>(); for (co.elastic.clients.elasticsearch.core.search.CompletionSuggestOption option : options) { Object obj = option.source(); ObjectMapper objectMapper = new ObjectMapper(); UrlIndexDto urlIndexDto = objectMapper.convertValue(obj, UrlIndexDto.class); urlIndexDtos.add(urlIndexDto); } return urlIndexDtos; } } } } } } return null; }
這樣就完成了查詢(xún)并返回的操作,下面我們講解下前端如何實(shí)現(xiàn)。
前端操作
我們使用react和antd來(lái)實(shí)現(xiàn),先定義組件和相關(guān)方法,如下所示:
<AutoComplete allowClear className={styles.input} options={options} onSelect={onSelect} value={input} onChange={async (e) => { setInput(e) debouncedOnChange(e); }}> <Input placeholder={'請(qǐng)輸入搜索內(nèi)容'} prefix={<SearchOutlined/>} size={'large'} onPressEnter={onSearch} /> </AutoComplete>
相關(guān)方法:
const [input, setInput] = useState('') const [options, setOptions] = useState([]) // 在組件外部定義防抖函數(shù) const debouncedOnChange = _.debounce(async (e) => { // 調(diào)用自動(dòng)補(bǔ)全接口 const res = await dispatch(webSearchSuggestion({ q: e })) const resData = res.payload.data if (resData && resData.length>0){ let list = [] resData.forEach(item =>{ console.log('item resData=', item) list.push({ label: item.title, value: item.title, url: item.url }) }) // 將數(shù)據(jù)設(shè)置到options中 setOptions(list) }else{ setOptions([]) } }, 500); // 搜索框回車(chē)事件,調(diào)用查詢(xún)接口(非自動(dòng)補(bǔ)全接口) async function onSelect(value, option){ dispatch(webSearch({ q: option.value, pageNum: 1, pageSize: 20 })) }
我們使用了ladash的防抖函數(shù)來(lái)實(shí)現(xiàn)搜索。
完成了準(zhǔn)備工作,我們來(lái)看看實(shí)現(xiàn)效果,如下所示:
注意
不是你在實(shí)體類(lèi)中定義了Completion
類(lèi)型的字段就ok了,要提前聲明Completion
才管用,親自踩過(guò)的坑?。?!
總結(jié)
完成這些代碼其實(shí)花費(fèi)了一點(diǎn)時(shí)間的,主要是不知道如何把devtools的查詢(xún)轉(zhuǎn)換成java代碼,并且我的版本是最新的,用的依賴(lài)包是上面提到的,所以寫(xiě)法上市面上沒(méi)有找到過(guò),完全靠自己搜索和chatgpt給的提示完成的。
到此這篇關(guān)于Java利用ElasticSearch實(shí)現(xiàn)自動(dòng)補(bǔ)全功能的文章就介紹到這了,更多相關(guān)Java ElasticSearch內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java查詢(xún)Elasticsearch數(shù)據(jù)根據(jù)指定id檢索(in查詢(xún))、sql權(quán)限過(guò)濾、多字段匹配檢索及數(shù)據(jù)排序
- Java使用ES?Client?調(diào)用滾動(dòng)查詢(xún)及Elasticsearch滾動(dòng)查詢(xún)Scrolling機(jī)制
- Java?Api實(shí)現(xiàn)Elasticsearch的滾動(dòng)查詢(xún)功能
- Java+ElasticSearch+Pytorch實(shí)現(xiàn)以圖搜圖功能
- Java中Elasticsearch 實(shí)現(xiàn)分頁(yè)方式(三種方式)
- 關(guān)于Java中配置ElasticSearch集群環(huán)境賬號(hào)密碼的問(wèn)題
- Java如何使用elasticsearch進(jìn)行模糊查詢(xún)
- JAVA使用ElasticSearch查詢(xún)in和not in的實(shí)現(xiàn)方式
- JAVA操作elastic?search的詳細(xì)過(guò)程
相關(guān)文章
關(guān)于@GetMapping和@GetMapping(value=““)的區(qū)別
這篇文章主要介紹了關(guān)于@GetMapping和@GetMapping(value=““)的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05Java線(xiàn)程的生命周期命名與獲取代碼實(shí)現(xiàn)
這篇文章主要介紹了Java線(xiàn)程的生命周期命名與獲取代碼實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04Java模擬多線(xiàn)程實(shí)現(xiàn)搶票代碼實(shí)例
這篇文章主要介紹了Java模擬多線(xiàn)程實(shí)現(xiàn)搶票,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01Java?從json提取數(shù)組并轉(zhuǎn)換為list的操作方法
這篇文章主要介紹了Java?從json提取出數(shù)組并轉(zhuǎn)換為list,使用getJSONArray()獲取到j(luò)sonarray后,再將jsonArray轉(zhuǎn)換為字符串,最后將字符串解析為L(zhǎng)ist列表,本文通過(guò)實(shí)例代碼給大家詳細(xì)講解,需要的朋友可以參考下2022-10-10一篇文章帶你搞懂Java restful 接口開(kāi)發(fā)
這篇文章主要介紹了Java restful 接口開(kāi)發(fā)的幾種方式(HTTPS),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2021-10-10Java設(shè)置JSON字符串參數(shù)編碼的示例詳解
在Java中創(chuàng)建JSON字符串,我們可以使用多個(gè)庫(kù),其中最流行的是Jackson、Gson和org.json,,下面給大家分享Java設(shè)置JSON字符串參數(shù)編碼的示例,感興趣的朋友一起看看吧2024-06-06