8.從零開始搭建基於SpringCloud的京東整站_內容管理微服務_使用Elasticsearch實現商品搜索

本次目標

後端:使用Elasticsearch實現商品搜索。
前端:使用Vue對查詢的商品列表進行展示。

使用Elasticsearch實現商品搜索

配置TransportClient客戶端

通過TransportClient發起對ES(Elasticsearch的簡稱)的索引創建、關鍵詞查詢等功能。

1. 在工程的POM.xm文件中添加相關依賴Jar包。

在父級工程中,添加TransportClient的版本管理:

<!--Elasticsearch-->
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>transport</artifactId>
    <version>5.5.2</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>5.5.2</version>
</dependency>

內容管理系統,添加TransportClient依賴:

<!--Elasticsearch-->
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>transport</artifactId>
</dependency>

這樣,內容管理微服務對TransportClient和Elasticsearch(前者依賴後者,版本需要統一)的Jar包都使用的5.5.2版本的了:
在這裏插入圖片描述
這裏需要注意,你服務器的版本需要和這裏的統一,否則會造成連接失敗。
2. 創建TransportClient對象,由Spring容器對其管理。

package liwen.zhao.config;

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 org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.net.InetAddress;
import java.util.List;

@Configuration
@ConfigurationProperties("config.es")
public class ESconfig {
    private List<String> nodes;
    
    public List<String> getNodes() {
        return nodes;
    }
    
    public void setNodes(List<String> nodes) {
        this.nodes = nodes;
    }
    
    private TransportClient transportClient;
    @Bean
    public TransportClient iniTransportClient(){
        transportClient=new PreBuiltTransportClient(Settings.EMPTY);
        
        //獲取配置文件中nodes節點信息中的ip和port
        for(String node: nodes){
            String ip=node.split(":")[0];
            String port=node.split(":")[1];
    
            try {
                InetSocketTransportAddress address= new InetSocketTransportAddress(InetAddress.getByName(ip), Integer.parseInt(port));
                transportClient.addTransportAddress(address);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return  transportClient;
    }
    
}


創建操作TransportClient的工具類:

package liwen.zhao.utils;

import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse;
import org.elasticsearch.client.IndicesAdminClient;
import org.elasticsearch.client.transport.TransportClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("esUtil")
public class ESUtil {
    @Autowired
    TransportClient transportClient;
    
    //創建索引
    public TransportClient  indexIsExists(String name){
        transportClient.admin().indices().prepareCreate(name).get().isAcknowledged();
        //拿到集羣索引管理對象
        IndicesAdminClient indicesAdminClient = transportClient.admin().indices();
        //判斷這個索引是否存在
        IndicesExistsResponse indicesExistsResponse = indicesAdminClient.prepareExists(name).get();
        if(!indicesExistsResponse.isExists()){
            throw  new RuntimeException("already exists");
        }else{
            return  transportClient;
        }
    }
    
}

配置文件中需要添加:

#Elasticsearch
config.es.nodes=192.168.43.88:9300

使用數據庫中的商品數據創建索引

1.控制層和業務層代碼實現

控制層:

@Controller
@RestController
@RequestMapping("/es")
public class ElasticsearchController {
    @Autowired
    private ElasticsearchService elasticsearchService;
    @RequestMapping("/createIndex")
    public SysResult createIndex(String indexName,String type){
        return elasticsearchService.createIndexByNameAndType(indexName,type);
    }
}

業務邏輯層:

package liwen.zhao.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import liwen.zhao.common.jd.pojo.Article;
import liwen.zhao.common.jd.vo.SysResult;
import liwen.zhao.mappers.ArticleMapper;
import liwen.zhao.utils.ESUtil;
import org.elasticsearch.client.transport.TransportClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class ElasticsearchServiceImpl implements ElasticsearchService {
    @Autowired
    ArticleMapper articleMapper;
    @Autowired
    private ESUtil esUtil;
    private ObjectMapper mapper=new ObjectMapper();
    @Override
    public SysResult createIndexByNameAndType(String indexName,String type) {
        try{
            TransportClient client = esUtil.indexIsExists(indexName);
            //創建索引成功
            //將document數據寫入到索引中 type
            //讀取數據庫數 0,100
            List<Article> articles = articleMapper.selectArticleByPage(0, 100);
            for(Article a:articles){
                //每次拿到一個商品對象
                //String aJson = mapper.writeValueAsString(p);
                Map<String ,String> articleMap=new HashMap<String ,String>();
                articleMap.put("title",a.getTitle());
                articleMap.put("content",a.getContent());
                articleMap.put("img",a.getImg());
                client.prepareIndex(indexName,type,a.getId()+"")
                        .setSource(articleMap).get();
            }
            return SysResult.ok();
        }catch (Exception e){
            e.printStackTrace();
            return SysResult.build(500,"索引創建失敗!",null);
        }
    }
}

2.完成商品索引的創建

在瀏覽器輸入:http://localhost/es/createIndex?indexName=jd&type=shop,將創建索引名稱爲jd,類型爲shop的索引。並將數據庫的100條數據錄入到Elasticsearch。

ps:這個操作直接暴露在外不太安全和正規,應該在後臺進行操作並添加認證授權流程。還是那句話,實現京東商城的每個細節不太現實,本次目標主要是爲了通過Elasticsearch實現一下搜索功能。
在這裏插入圖片描述
在這裏插入圖片描述

使用Vue對查詢的商品列表進行展示

準備商品數據查詢的接口:
在這裏插入圖片描述

前端代碼-數據獲取:

<script type="application/javascript">
	var vm = new Vue({
		el:"#vue",
		data:{
			text:"",
			page:1,
			rows:10,
			shops:[]
		},
		methods:{
			submit:function () {
				var ts=this;
				const url="/es/search";
				let datas = {params:{"text":this.text,"page":this.page,"rows":this.rows}};

				axios.get(url,datas).then(function(resp){
					console.log(resp.data);
					ts.shops=resp.data;
				});

			}
		}
	})
</script>

前端代碼-數據綁定:

<!-- 商品列表 start-->
<div class="goodslist mt10">
	<ul>
		<li v-for="shop in shops">
			<dl>
				<dt><a href=""><img  v-bind:src="shop.img" alt="" /></a></dt>
				<dd><a href="">{{shop.title}}</a></dt>
				<dd><strong>¥{{shop.price}}</strong></dt>
				<dd><a href=""><em>已有10人評價</em></a></dt>
			</dl>
		</li>

	</ul>
</div>

效果展示

搜索“手機”:
在這裏插入圖片描述
在這裏插入圖片描述

我們看到,前兩個商品,和手機密切相關,搜出來了,權重最高,排在了前面。第三個商品,機油裏有“機”,次相關。後面兩個商品,手錶裏有“手”,也是次相關。

總結

本案例,通過elasticsearch實現了商品搜索功能。 除建立索引用到了數據庫,其它過程都是Elasticsearch實現的。 這樣既實現了精準搜索,又減小了數據庫訪問壓力。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章