需求
將商品表數據全量更新至ES索引
商品索引支持Suggester自動補全,支持過濾商品enable和delete_status狀態,只篩選啟用且未刪除的商品
Suggester與普通搜索區別:ES將Suggest機器依賴的字段放在堆內存,實現近實時的搜索提示功能
es安裝ik分詞插件
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.7.0/elasticsearch-analysis-ik-7.7.0.zip
配置logstash配置文件
input { stdin { } jdbc { # 連接的數據庫地址和哪一個數據庫,指定編碼格式,禁用SSL協議,設定自動重連 jdbc_connection_string => "jdbc:mysql://{你的MySQL}:3306/shop-server?characterEncoding=UTF-8&useSSL=false&autoReconnect=true" # 你的賬戶密碼 jdbc_user => "{你的用戶}" jdbc_password => "{你的密碼}" # 連接數據庫的驅動包,建議使用絕對地址 jdbc_driver_library => "/data/logstash-6.4.0/bin/mysql/mysql-connector-java-5.1.22-bin.jar" # 這是不用動就好 jdbc_driver_class => "com.mysql.jdbc.Driver" jdbc_paging_enabled => "true" jdbc_page_size => "2000" #處理中文亂碼問題 codec => plain { charset => "UTF-8"} #使用其它字段追蹤,而不是用時間 use_column_value => true #追蹤的字段 tracking_column => app_goods_id record_last_run => true statement => "SELECT g.app_goods_id, g.goods_id, g.goods_name, g.goods_name AS suggest, g.collect_count, g.sale, g.alone_price, g.enable, g.delete_status, (SELECT GROUP_CONCAT( goods_type_id ) FROM db_goods_type_link WHERE goods_id = g.goods_Id ) AS goods_type_id, CASE WHEN g.alone_price > 301 THEN 100 WHEN g.alone_price > 101 THEN 300 WHEN g.alone_price > 51 THEN 500 WHEN g.alone_price > 0 THEN 400 ELSE 0 END price_score, CASE b.brand_level WHEN 1 THEN 500 WHEN 2 THEN 300 WHEN 3 THEN 100 WHEN 4 THEN 0 ELSE 0 END brand_score FROM db_app_goods g LEFT JOIN db_brand b ON g.brand_id = b.brand_id LIMIT 2000" #上一個sql_last_value值的存放文件路徑, 必須要在文件中指定字段的初始值 last_run_metadata_path => "/data/logstash-6.4.0/bin/mysql/goods.log" jdbc_default_timezone => "Asia/Shanghai" #statement_filepath => "mysql/jdbc.sql" #是否清除 last_run_metadata_path 的記錄,如果為真那么每次都相當於從頭開始查詢所有的數據庫記錄 clean_run => false # 這是控制定時的,重復執行導入任務的時間間隔,第一位是分鍾 schedule => "* */1 * * *" type => "jdbc" } } filter { json { source => "message" remove_field => ["message"] } } output { elasticsearch { # 要導入到的Elasticsearch所在的主機 hosts => "127.0.0.1:9200" # 要導入到的Elasticsearch的索引的名稱 index => "goods" # 類型名稱(類似數據庫表名) #document_type => "appgood" # 主鍵名稱(類似數據庫主鍵) document_id => "%{app_goods_id}" # es 賬號 user => {你的ES用戶} password => {你的ES密碼} # 這里配置為當前logstash的相對路徑,該文件配置了輸出的Mapping template => "mysql/goods_mapping.json" template_name => "goods" template_overwrite => true } stdout { # JSON格式輸出 codec => json_lines } }
創建商品索引映射goods_mapping.json
{ "template": "goods", "settings": { "index.refresh_interval": "1s" }, "index_patterns": ["goods"], "mappings": { "properties": { "suggest": { "type": "completion", "analyzer": "ik_smart", "search_analyzer": "ik_smart", "contexts": [{ "name": "enable_cat", "type": "category", "path": "enable" }, { "name": "delete_status_cat", "type": "category", "path": "delete_status" } ] }, "goods_name": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_smart" }, "goods_type_id": { "type": "keyword" }, "app_goods_id": { "type": "long" }, "goods_id": { "type": "long" }, "collect_count": { "type": "integer" }, "sale": { "type": "integer" }, "alone_price": { "type": "double" }, "brand_score": { "type": "integer" }, "enable": { "type": "keyword" }, "delete_status" :{ "type": "keyword" } } } }
使用logstash -f {goods配置文件}啟動logstash,logstash將自動從數據庫查詢並以Mapping創建索引
查看索引是否映射成功
GET goods_dev/_mapping
結果:
{ "goods_dev" : { "mappings" : { "properties" : { "@timestamp" : { "type" : "date" }, "@version" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } }, "alone_price" : { "type" : "double" }, "app_goods_id" : { "type" : "long" }, "brand_score" : { "type" : "integer" }, "collect_count" : { "type" : "integer" }, "delete_status" : { "type" : "keyword" }, "enable" : { "type" : "keyword" }, "goods_id" : { "type" : "long" }, "goods_name" : { "type" : "text", "analyzer" : "ik_max_word", "search_analyzer" : "ik_smart" }, "goods_type_id" : { "type" : "keyword" }, "price_score" : { "type" : "long" }, "sale" : { "type" : "integer" }, "suggest" : { "type" : "completion", "analyzer" : "ik_smart", "preserve_separators" : true, "preserve_position_increments" : true, "max_input_length" : 50, "contexts" : [ { "name" : "enable_cat", "type" : "CATEGORY", "path" : "enable" }, { "name" : "delete_status_cat", "type" : "CATEGORY", "path" : "delete_status" } ] }, "type" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } } } } } }
使用前綴ContextComplitationSuggester進行聯想詞查詢
POST goods_dev/_search?pretty { "_source": "suggest", "suggest": { "my-suggest":{ "prefix":"肌膚", "completion":{ "field":"suggest", "skip_duplicates":true, "size":10, "contexts":{ "enable_cat":{ "context":1 }, "delete_status_cat":{ "context":0 } } } } } }
結果:
{ "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" : { "my-suggest" : [ { "text" : "肌膚", "offset" : 0, "length" : 2, "options" : [ { "text" : "“肌膚吸塵器123”香港CHICELAN槿念煙酰胺磨砂沐浴露溫和雙效去角質一瓶=沐浴露+磨砂膏", "_index" : "goods_dev", "_type" : "_doc", "_id" : "1323938082604585019", "_score" : 1.0, "_source" : { "suggest" : "“肌膚吸塵器123”香港CHICELAN槿念煙酰胺磨砂沐浴露溫和雙效去角質一瓶=沐浴露+磨砂膏" }, "contexts" : { "enable_cat" : [ "1" ] } }, { "text" : "“肌膚吸塵器”香港CHICELAN槿念煙酰胺磨砂沐浴露溫和雙效去角質一瓶=沐浴露+磨砂膏", "_index" : "goods_dev", "_type" : "_doc", "_id" : "1323894411586834447", "_score" : 1.0, "_source" : { "suggest" : "“肌膚吸塵器”香港CHICELAN槿念煙酰胺磨砂沐浴露溫和雙效去角質一瓶=沐浴露+磨砂膏" }, "contexts" : { "delete_status_cat" : [ "0" ] } } ] } ] } }
使用SpringDataElasticsearch進行JavaAPI查詢
新建一個固定suggest查詢對象,該對象構建一個查詢context,類似於上面的
"contexts":{ "enable_cat":{ "context":1 }, "delete_status_cat":{ "context":0 } }
/** * 固定的suggest查詢對象 */ private static Map<String, List<? extends ToXContent>> SUGGESTION_CONTEXT = null; static { CategoryQueryContext enableCat = CategoryQueryContext.builder().setCategory("1").build(); CategoryQueryContext deleteStatusCat = CategoryQueryContext.builder().setCategory("0").build(); Map<String, List<? extends ToXContent>> contexts = new HashMap<>(); List<CategoryQueryContext> list = new ArrayList<>(1); list.add(enableCat); contexts.put("enable_cat", list); List<CategoryQueryContext> list2 = new ArrayList<>(1); list2.add(deleteStatusCat); contexts.put("delete_status_cat",list2); SUGGESTION_CONTEXT = contexts; }
根據關鍵字聯想查詢方法
@Override public List<String> associate(String keyword) { //使用suggest進行標題聯想 CompletionSuggestionBuilder suggest = SuggestBuilders.completionSuggestion("suggest").prefix(keyword).skipDuplicates(true).size(10).contexts(SUGGESTION_CONTEXT); SuggestBuilder suggestBuilder = new SuggestBuilder(); suggestBuilder.addSuggestion("goodsNameSuggest",suggest); //查詢 SearchResponse goodsNameSuggestResp = elasticsearchRestTemplate.suggest(suggestBuilder, goodsIndexName); Suggest.Suggestion<? extends Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option>> goodsNameSuggest = goodsNameSuggestResp .getSuggest().getSuggestion("goodsNameSuggest"); //處理返回 List<String> collect = goodsNameSuggest.getEntries().stream().map(x -> x.getOptions().stream().map(y->y.getText().toString()).collect(Collectors.toList())).findFirst().get(); return CollectionUtils.isEmpty(collect)?Collections.emptyList():collect; }
接口測試
接口傳遞keyword關鍵字"韓版",返回
{ "code": 200, "msg": "操作成功", "timestamp": "1605173186443", "data": [ "韓版時尚中長款襯衫 Because-t2041", "韓版淑女純色休閑褲 Holicholic-sp26265", "韓版簡約時尚連衣裙 Happy10-ds1009573", "韓版簡約純色襯衫 Holicholic-t26070", "韓版簡約經典半身裙 Maybe-baby-sp30591", "韓版簡約經典女褲套裝 Holicholic-ds26260", "韓版純色休閑T恤 Holicholic-t26074" ] }
鏈接:https://www.jianshu.com/p/c78011dd9028
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。