1. 程式人生 > >Elasticsearch5基於completion suggester實現提示詞(類京東淘寶)

Elasticsearch5基於completion suggester實現提示詞(類京東淘寶)

支援拼音首字母,全拼,和中文匹配提示,如下



1、建立index,設定setting

curl -XPUT "http://localhost:9200/medcl/" -d '
{
	"index": {
		"analysis": {
			"analyzer": {
				"default": {
					"tokenizer": "ik_max_word"
				},
				"pinyin_analyzer": {
					"tokenizer": "shopmall_pinyin"
				},
				"first_py_letter_analyzer": {
					"tokenizer": "first_py_letter"
				},
				"full_pinyin_letter_analyzer": {
					"tokenizer": "full_pinyin_letter"
				}
			},
			"tokenizer": {
				"shopmall_pinyin": {
					"keep_joined_full_pinyin": "true",
					"keep_first_letter": "true",
					"keep_separate_first_letter": "false",
					"lowercase": "true",
					"type": "pinyin",
					"limit_first_letter_length": "16",
					"keep_original": "true",
					"keep_full_pinyin": "true",
					"keep_none_chinese_in_joined_full_pinyin": "true"
				},
				"first_py_letter": {
					"type": "pinyin",
					"keep_first_letter": true,
					"keep_full_pinyin": false,
					"keep_original": false,
					"limit_first_letter_length": 16,
					"lowercase": true,
					"trim_whitespace": true,
					"keep_none_chinese_in_first_letter": false,
					"none_chinese_pinyin_tokenize": false,
					"keep_none_chinese": true,
					"keep_none_chinese_in_joined_full_pinyin": true
				},
				"full_pinyin_letter": {
					"type": "pinyin",
					"keep_separate_first_letter": false,
					"keep_full_pinyin": false,
					"keep_original": false,
					"limit_first_letter_length": 16,
					"lowercase": true,
					"keep_first_letter": false,
					"keep_none_chinese_in_first_letter": false,
					"none_chinese_pinyin_tokenize": false,
					"keep_none_chinese": true,
					"keep_joined_full_pinyin": true,
					"keep_none_chinese_in_joined_full_pinyin": true
				}
			}
		}
	}
}'

2、mapping

curl -XPOST http://localhost:9200/medcl/folks/_mapping -d'
{
	"folks": {
		"properties": {
			"name": {
				"type": "completion",
				"fields": {
					"pinyin": {
						"type": "completion",
						"analyzer": "pinyin_analyzer"
					},
					"keyword_pinyin": {
						"type": "completion",
						"analyzer": "full_pinyin_letter_analyzer"
					},
					"keyword_first_py": {
						"type": "completion",
						"analyzer": "first_py_letter_analyzer"
					}
				}
			}
		}
	}
}'

3、初始化測試資料

curl -XPOST http://localhost:9200/medcl/folks/ -d'{"name":"蘋果"}'

4、搜尋

curl -XPOST http://localhost:9200/medcl/folks/_search -d '
{
  "size": 0,
  "_source": "name",
  "suggest": {
    "my-suggest-1": {
      "text": "蘋",
      "completion": {
        "field": "name",
        "size": 20
      }
    }
  }
}'

5、結果

{
	"took": 2,
	"timed_out": false,
	"_shards": {
		"total": 5,
		"successful": 5,
		"failed": 0
	},
	"hits": {
		"total": 0,
		"max_score": 0,
		"hits": []
	},
	"suggest": {
		"my-suggest-1": [{
			"text": "蘋",
			"offset": 0,
			"length": 1,
			"options": [{
					"text": "蘋果",
					"_index": "medcl",
					"_type": "folks",
					"_id": "AWRLJ9lrsB4QSA8b-FrJ",
					"_score": 1,
					"_source": {
						"name": "蘋果"
					}
				}
			]
		}]
	}
}

6、程式碼實現,基於elasticsearch5.x版本

* 1、檢測搜尋詞是中文還是拼音
* 2、若是中文,直接按照name欄位提示
* 3、若是拼音(拼音+漢字),先按照name.keyword_pinyin獲取,若是無結果按照首字母name.keyword_first_py獲取

Java程式碼:

package test;

import java.net.UnknownHostException;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Pattern;

import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class EsSuggestTest01 {

    private static Client client;

    @Before
    public void init() throws UnknownHostException {
        client = ElasticsearchConfiguration.getClient();
    }

    @After
    public void close() {
    	ElasticsearchConfiguration.close();
    }
    
    @Test
    public void test(){
    	String index = "medcl";
    	String type = "folks";
    	QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
    	String text = "蘋";
    	String field = "name";
		
    	if(checkLetter(text)) {
    	    field = "name.keyword_pinyin";	
    	} else if(checkChinese(text)) {
    	    field = "name";
    	} else {
    	    field = "name.keyword_pinyin";
	}
		
	Set<String> results = getSuggestWord(index, type, field, text, queryBuilder);
	//結果為空且是拼音,可以嘗試拼音首字母提示
	if(results.size() == 0 && checkLetter(text)) {
		field = "nicknames.nicknameSuggest.keyword_first_py";
		results = getSuggestWord(index, type, field, text, queryBuilder);
	}
		
    	for (String result : results) {
    	    System.out.println(result);
    	}
    }
    
	/**
	  * Description:提示詞,支援中文、拼音、首字母等(注意要去掉_source資訊)
	  * 
	  * 1、檢測搜尋詞是中文還是拼音
      * 2、若是中文,直接按照name欄位提示
      * 3、若是拼音(拼音+漢字),先按照name.keyword_pinyin獲取,若是無結果按照首字母name.keyword_first_py獲取
	  * 
	  * SearchRequestBuilder的size要設定為0,否則顯示hits結果
	  * searchRequestBuilder.setSize(0);
	  * 
	  * _source 由於磁碟讀取和網路傳輸開銷,可以影響效能的大小,為了節省一些網路開銷,請從_source 使用源過濾中過濾掉不必要的欄位以最小化 _source大小
	  * 可以採用過濾的形式,也可以直接不顯示_source
	  * 1、searchRequestBuilder.setFetchSource("name", null);     過濾形式
	  * 2、searchRequestBuilder.setFetchSource(false)   直接不顯示_source
	  * 
	  * @author wangweidong
	  * CreateTime: 2018年6月28日 下午2:39:47
	  *
	  * @param index
	  * @param type
	  * @param field
	  * @param text
	  * @return
	 */
	 public static Set<String> getSuggestWord(String index, String type, String field, String text, QueryBuilder queryBuilder) {
		//過濾相同的提示詞,Es5.2版本不支援過濾掉重複的建議,故需自己對ES返回做去重處理,Es6.1以上版本可以通過skip_duplicates欄位處理,skip_duplicates表示是否應過濾掉重複的建議(預設為false)
		Set<String> results = new TreeSet<String>();
		CompletionSuggestionBuilder suggestionBuilder = new CompletionSuggestionBuilder(field);
	   	suggestionBuilder.text(text);
	   	suggestionBuilder.size(20);
	      
	   	SuggestBuilder suggestBuilder = new SuggestBuilder();
	   	suggestBuilder.addSuggestion("my-suggest-1", suggestionBuilder);
	   	
	   	SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index).setTypes(type);
	   	searchRequestBuilder.setExplain(false);
	   	searchRequestBuilder.setSize(0);
	   	searchRequestBuilder.setQuery(queryBuilder);
	   	searchRequestBuilder.suggest(suggestBuilder);
	   	searchRequestBuilder.setFetchSource(false);
	//   	searchRequestBuilder.setFetchSource("name", null);
	   	
	   	SearchResponse resp = searchRequestBuilder.execute().actionGet();
	   	Suggest sugg = resp.getSuggest();
	   	CompletionSuggestion suggestion = sugg.getSuggestion("my-suggest-1");
	   	List<CompletionSuggestion.Entry> list = suggestion.getEntries();
	   	for (int i = 0; i < list.size(); i++) {
	   		List<? extends Suggest.Suggestion.Entry.Option> options = list.get(i).getOptions();  
	   		for (Suggest.Suggestion.Entry.Option op : options) {
	   			results.add(op.getText().toString());
			}
	   	}
	   	return results;
    }
    
    /**
     * 只包含字母
     * @return 驗證成功返回true,驗證失敗返回false
     */
    public static boolean checkLetter(String cardNum) { 
        String regex = "^[A-Za-z]+$";
        return Pattern.matches(regex, cardNum); 
    }
    
    /**
     * 驗證中文
     * @param chinese 中文字元
     * @return 驗證成功返回true,驗證失敗返回false
     */ 
    public static boolean checkChinese(String chinese) { 
        String regex = "^[\u4E00-\u9FA5]+$"; 
        return Pattern.matches(regex,chinese); 
    } 
}

import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;

import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List;

public class ElasticsearchConfiguration {

    private static TransportClient client;

    private static String clusterName;
    private static List<String> clusterNodes;

    static {
        clusterName = "shop-es";
        clusterNodes = Arrays.asList("http://172.16.32.6:9300","http://172.16.32.8:9300");
    }

    private ElasticsearchConfiguration() {
    }

    public static Client getClient() throws UnknownHostException {
        Settings settings = Settings.builder().put("cluster.name", clusterName).build();
        client = new PreBuiltTransportClient(settings);
        for (String node : clusterNodes) {
            URI host = URI.create(node);
            client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(host.getHost()), host.getPort()));
        }
        return client;
    }

    public static void close() {
        client.close();
    }
}

相關推薦

Elasticsearch5基於completion suggester實現提示京東

支援拼音首字母,全拼,和中文匹配提示,如下1、建立index,設定settingcurl -XPUT "http://localhost:9200/medcl/" -d ' { "index": { "analysis": { "analyzer": {

Android 音視頻深入 十五 FFmpeg 實現基於Rtmp協議的推流附源碼下載

音視頻 FFmpeg Rtmp 推流 源碼地址https://github.com/979451341/Rtmp 1.配置RTMP服務器 這個我不多說貼兩個博客分別是在mac和windows環境上的,大家跟著弄MAC搭建RTMP服務器https://www.jianshu.com/p/6fce

SSM整合系列之 基於Shiro框架實現自動登入RememberMe

一、前言:Shiro框架提供了記住我(RememerMe)的功能,比如我們訪問一些網站,關閉了瀏覽器,下次再開啟還是能記住你是誰,下次訪問的時候無需登入即可訪問,本文將實現記住我的功能。 專案git地址:https://github.com/gitcaiqing/SSM_DEMO.git

.NET Core微服務之基於Jenkins+Docker實現持續部署Part 1

一、CI, CD 與Jenkins   網際網路軟體的開發和釋出,已經形成了一套標準流程,最重要的組成部分就是持續整合(Continuous integration,簡稱 CI) => 持續整合指的是,頻繁地(一天多次)將程式碼整合到主幹。   它的好處主要有兩個: 快速發現錯

基於Flex 4.6實現 Picture Slide 圖片滑動展示效果

之前專案中有用到這種效果,圖片幻燈顯示,一般來說JS實現的較多,Flex的話,貌似之前有找到過Flex3的實現方案,so 我就借鑑一下咯 當然根據實際應用情況,將程式碼升級到Flex4,然後又根據自己的應用需要增加了些控制效果。 閒話不多說,先上程式碼 PictureSli

基於python,scrapy,redis實現主從式分散式的一種master-slave爬蟲

前言這是本人的第一篇部落格,感觸還是很多的,最近在幫朋友做一個分散式爬蟲的論文,遇到很多坑,不過已經一一填平,廢話不多說啦。分類(1)主從分散式爬蟲:由一臺master伺服器, 來提供url的分發, 維護待抓取url的list。由多臺slave伺服器執行網頁抓取功能, sla

【C++】基於“stringstream+getline”實現字串分割split

哇... 最近在練習C++程式設計,遇到一個題目需要用到字串分割(類似python的split函式)。C++並沒有提供關於這個函式的功能,所以要自己實現。 就在此時,看到字串流 stringstream 這個高階的類,功能非常強大,如數字與字串之間的轉換。 本文只介紹基於“

基於vue2.x實現loading bar載入進度條元件

在這之前,我更新了有關一個單選框與複選框的元件實現,有興趣的小夥伴也可以瞭解一下,今天我們來介紹一下loading bar 元件的實現原理。 實現思路 整個元件ui部分有兩部分組成

【開源專案系列】如何基於 Spring Cache 實現多級快取同時整合本地快取 Ehcache 和分散式快取 Redis

## 一、快取 當系統的併發量上來了,如果我們頻繁地去訪問資料庫,那麼會使資料庫的壓力不斷增大,在高峰時甚至可以出現數據庫崩潰的現象。所以一般我們會使用快取來解決這個資料庫併發訪問問題,使用者訪問進來,會先從快取裡查詢,如果存在則返回,如果不存在再從資料庫裡查詢,最後新增到快取裡,然後返回給使用者,當然了,接

如何基於 echarts 在柱狀圖或條形圖上實現轉換率?有想法嗎?

[TOC] > 我是沒想法啦(一開始)。其實,好久沒接觸 echarts 了,至少有一年多了,想起以前折騰地圖的情景了

K8s 1.18.6版本基於 ingress-nginx 實現金絲雀釋出灰度釋出

# K8s 1.18.6版本基於 ingress-nginx 實現金絲雀釋出(灰度釋出) ## 環境 | 軟體 | 版本 | | ------------------------ | ------- | | kubernetes |

基於Hi3559AV100 RFCN實現細節解析-2RFCN資料流分析

  下面隨筆系列將對Hi3559AV100 RFCN實現細節進行解析,整個過程涉及到VI、VDEC、VPSS、VGS、VO、NNIE,其中涉及的內容,大家可以參考之前我寫的部落格: Hi3559AV100的VI細節處理說明: https://www.cnblogs.com/iFrank/p/14374658.

圖像切割—基於圖的圖像切割Graph-Based Image Segmentation

子圖 衡量標準 content 彩色 cep 期待 mean 定義 筆記  圖像切割—基於圖的圖像切割(Graph-Based Image Segmentation) Reference: Efficient Graph-Ba

python-叠代器實現異步在串行中

pro log cer def pri 通過 返回值 UC ons import timedef consumer(name): print(‘%s 準備吃包子啦!‘ %name) while True: baozi = yield #yield不

SpringBoot + CXF快速實現SOAP WebService支持Basic Auth

9.png service 手動 1.8 項目 ref tina poi 攔截器 嘮叨兩句 講真,SOAP跟現在流行的RESTful WebService比起來顯得很難用。冗余的XML文本信息太多,可讀性差,它的請求信息有時很難手動構造,不太好調試。不過說歸說,對某些企業

819. Most Common Word 統計高頻暫未被禁止

AS was ase ctu 處理 clas isn IT 輸出 [抄題]: Given a paragraph and a list of banned words, return the most frequent word that is not in the lis

Android lrucache 實現與使用Android內存優化

hashmap 獲取 fin pub viewpage map.entry ring zhong 實現 什麽是LruCache? LruCache實現原理是什麽? 這兩個問題其實可以作為一個問題來回答,知道了什麽是 LruCache,就只然而然的知道 LruCac

JAVA實現郵件驗證註冊功能中使用

原始碼: 連結:https://pan.baidu.com/s/1iSRybqDdzYU8apEs1OtQBw 提取碼:q0gb  易郵 and foxmail 連結:https://pan.baidu.com/s/1woOxn-UjmoALCQDjFuGAQQ&n

javaleetcode804 唯一摩爾斯密碼Unique Morse Code Words

題目描述: 國際摩爾斯密碼定義一種標準編碼方式,將每個字母對應於一個由一系列點和短線組成的字串, 比如: "a" 對應 ".-", "b" 對應 "-...", "c" 對應 "-.-.",

08有關設計和實現的問題的結構關系

怎麽 包含 let 層次 維護 大量 raw int() 模式 一. 類內部的設計和實現 ? 給類定義合理的接口,對於創建高質量程序起到了關鍵作用。然而,類內部的設計和實現也同樣重要。這裏主要論述關於包含、繼承、成員函數和數據成員、類之間的耦合性、構造函數、值對象與引用對象