1. 程式人生 > >第9講 9. ElasticSearch中文分詞smartcn

第9講 9. ElasticSearch中文分詞smartcn

1,安裝中文外掛,參考文件:http://www.cruiseloveashley.com/news/?7917.html
2,測試分詞效果,/_analyze/路徑, analyzer為key,smartcn為value,見參考文件:http://www.cruiseloveashley.com/news/?7917.html
3,新建索引film2,分片5,副本1,新建結構,title和content要指定analyzer,smartcn分詞
9._ElasticSearch中文分詞smartcn
新建結構,
9._ElasticSearch中文分詞smartcn
4, 新增測試資料:見附件
5,寫Java程式碼,實現smart 分詞,

   常規程式碼也可以起到分詞的效果,下面的是常規程式碼以及解釋:
    @Test
    public

 void searchByCondition() throws Exception{
//     SearchRequestBuilder srb = client.prepareSearch("film").setTypes("dongzuo");
       SearchRequestBuilder srb = client.prepareSearch("film2").setTypes("dongzuo");
       SearchResponse sr = srb.setQuery(QueryBuilders.matchQuery
("title", "戰"))
           .setFetchSource(new String[]{"title","price"}, null)
           .execute()
           .actionGet();
       SearchHits hits = sr.getHits();
       for
 (SearchHit hit : hits) {
           System.out.println(hit.getSourceAsString());
       }
    }
對以上程式碼解釋:再新增資料的時候,film 使用的是預設的標準分詞器,film2使用的是smartcn分詞器。使用標準分詞器,會把每一個漢字拆分開,搜尋到的結果將是兩條記錄;使用smartcn分詞器,會把一些單詞看成是一個詞,搜尋結果將是一條記錄。
film 對應的結果:
    {"price":"38","title":"戰狼2"}
   {"price":"55","title":"星球大戰8:最後的絕地武士"}
film2 對應的結果:
   {"price":"38","title":"戰狼2"}

Java使用smartcn分詞:程式碼:
package com.cruise;

import java.net.InetAddress;

import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TestPartSearch {

    private static String host="192.168.245.40";
    private static int port=9300;
    private TransportClient client =null;
    public static final String ANALYZER="smartcn";
    public static final String CLUSTER_NAME="my-application";
    private static Settings.Builder settings=Settings.builder().put("cluster.name",CLUSTER_NAME);
    
    
    @SuppressWarnings({ "resource", "unchecked" })
    @Before
    public void getClient() throws Exception{
       client = new PreBuiltTransportClient(settings.build())
              .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(host),port));
    }
    
    @After
    public void close(){
       if(client!=null){
           client.close();
       }
    }
    
    @Test
    public void searchByCondition() throws Exception{
       SearchRequestBuilder srb = client.prepareSearch("film2").setTypes("dongzuo");
       SearchResponse sr = srb.setQuery(QueryBuilders.matchQuery("title", "最後狼").analyzer(ANALYZER))
           .setFetchSource(new String[]{"title","price"}, null)
           .execute()
           .actionGet();
       SearchHits hits = sr.getHits();
       for (SearchHit hit : hits) {
           System.out.println(hit.getSourceAsString());
       }
    }
}



6,寫Java程式碼,實現多欄位分詞查詢,
 package com.cruise;

import java.net.InetAddress;

import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TestPartSearch {

    private static String host="192.168.245.40";
    private static int port=9300;
    private TransportClient client =null;
    public static final String ANALYZER="smartcn";
    public static final String CLUSTER_NAME="my-application";
    private static Settings.Builder settings=Settings.builder().put("cluster.name",CLUSTER_NAME);
    
    
    @SuppressWarnings({ "resource", "unchecked" })
    @Before
    public void getClient() throws Exception{
       client = new PreBuiltTransportClient(settings.build())
              .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(host),port));
    }
    
    @After
    public void close(){
       if(client!=null){
           client.close();
       }
    }
    
    @Test
    public void searchByCondition() throws Exception{
       SearchRequestBuilder srb = client.prepareSearch("film2").setTypes("dongzuo");
       SearchResponse sr = srb.setQuery(QueryBuilders.multiMatchQuery("鐵拳冷鋒","title","content").analyzer(ANALYZER))
           .setFetchSource(new String[]{"title","price"}, null)
           .execute()
           .actionGet();
       SearchHits hits = sr.getHits();
       for (SearchHit hit : hits) {
           System.out.println(hit.getSourceAsString());
       }
    }
}

以下film2測試資料

package com.cruise;

import java.net.InetAddress;

import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;

public class TestFilm {

	private static String host="192.168.245.40";
	private static int port=9300;
	private TransportClient client =null;
	public static final String CLUSTER_NAME="my-application";
	private static Settings.Builder settings=Settings.builder().put("cluster.name",CLUSTER_NAME);
	
	
	@SuppressWarnings({ "resource", "unchecked" })
	@Before
	public void getClient() throws Exception{
		client = new PreBuiltTransportClient(settings.build())
				.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(host),port));
	}
	
	@After
	public void close(){
		if(client!=null){
			client.close();
		}
	}
	
	@Test
	public void testIndex() throws Exception{
		
     JsonArray jsonArray=new JsonArray();
    	
    	JsonObject jsonObject=new JsonObject();
    	jsonObject.addProperty("title", "前任3:再見前任");
    	jsonObject.addProperty("publishDate", "2017-12-29");
    	jsonObject.addProperty("content", "一對好基友孟雲(韓庚 飾)和餘飛(鄭愷 飾)跟女友都因為一點小事宣告分手,並且“拒絕挽回,死不認錯”。兩人在夜店、派對與交友軟體上放飛人生第二春,大肆慶祝“黃金單身期”,從而引發了一系列好笑的故事。孟雲與女友同甘共苦卻難逃“五年之癢”,餘飛與女友則棋逢敵手相愛相殺無絕期。然而現實的“打臉”卻來得猝不及防:一對推拉糾結零往來,一對糾纏互懟全交代。兩對戀人都將面對最終的選擇:是再次相見?還是再也不見?");
    	jsonObject.addProperty("director", "田羽生");
    	jsonObject.addProperty("price", "35");
    	jsonArray.add(jsonObject);
    	
    	
    	JsonObject jsonObject2=new JsonObject();
    	jsonObject2.addProperty("title", "機器之血");
    	jsonObject2.addProperty("publishDate", "2017-12-29");
    	jsonObject2.addProperty("content", "2007年,Dr.James在半島軍火商的支援下研究生化人。研究過程中,生化人安德烈發生基因突變大開殺戒,將半島軍火商殺害,並控制其組織,接管生化人的研究。Dr.James僥倖逃生,只好尋求警方的保護。特工林東(成龍 飾)不得以離開生命垂危的小女兒西西,接受證人保護任務...十三年後,一本科幻小說《機器之血》的出版引出了黑衣生化人組織,神祕駭客李森(羅志祥 飾)(被殺害的半島軍火商的兒子),以及隱姓埋名的林東,三股力量都開始接近一個“普通”女孩Nancy(歐陽娜娜 飾)的生活,想要得到她身上的祕密。而黑衣人幕後受傷隱藏多年的安德烈也再次出手,在多次纏鬥之後終於抓走Nancy。林東和李森,不得不以身犯險一同前去解救,關鍵時刻卻發現李森竟然是被殺害的半島軍火商的兒子,生化人的實驗記錄也落入了李森之手......");
    	jsonObject2.addProperty("director", "張立嘉");
    	jsonObject2.addProperty("price", "45");
    	jsonArray.add(jsonObject2);
    	
    	JsonObject jsonObject3=new JsonObject();
    	jsonObject3.addProperty("title", "星球大戰8:最後的絕地武士");
    	jsonObject3.addProperty("publishDate", "2018-01-05");
    	jsonObject3.addProperty("content", "《星球大戰:最後的絕地武士》承接前作《星球大戰:原力覺醒》的劇情,講述第一軍團全面侵襲之下,蕾伊(黛西·雷德利 Daisy Ridley 飾)、芬恩(約翰·博耶加 John Boyega 飾)、波·達默龍(奧斯卡·伊薩克 Oscar Isaac 飾)三位年輕主角各自的抉 擇和冒險故事。前作中覺醒強大原力的蕾伊獨自尋訪隱居的絕地大師盧克·天行者(馬克·哈米爾 Mark Hamill 飾),在後者的指導下接受原力訓練。芬恩接受了一項幾乎不可能完成的任務,為此他不得不勇闖敵營,面對自己的過去。波·達默龍則要適應從戰士向領袖的角色轉換,這一過程中他也將接受一些血的教訓。");
    	jsonObject3.addProperty("director", "萊恩·約翰遜");
    	jsonObject3.addProperty("price", "55");
    	jsonArray.add(jsonObject3);
    	
    	JsonObject jsonObject4=new JsonObject();
    	jsonObject4.addProperty("title", "羞羞的鐵拳");
    	jsonObject4.addProperty("publishDate", "2017-12-29");
    	jsonObject4.addProperty("content", "靠打假拳混日子的艾迪生(艾倫 飾),本來和正義感十足的體育記者馬小(馬麗 飾)是一對冤家,沒想到因為一場意外的電擊,男女身體互換。性別錯亂後,兩人互坑互害,引發了拳壇的大地震,也揭開了假拳界的祕密,惹來一堆麻煩,最終兩人在“卷蓮門”副掌門張茱萸(沈騰 飾)的指點下,向惡勢力揮起了羞羞的鐵拳。");
    	jsonObject4.addProperty("director", "宋陽 / 張吃魚");
    	jsonObject4.addProperty("price", "35");
    	jsonArray.add(jsonObject4);
    	
    	JsonObject jsonObject5=new JsonObject();
    	jsonObject5.addProperty("title", "戰狼2");
    	jsonObject5.addProperty("publishDate", "2017-07-27");
    	jsonObject5.addProperty("content", "故事發生在非洲附近的大海上,主人公冷鋒(吳京 飾)遭遇人生滑鐵盧,被“開除軍籍”,本想漂泊一生的他,正當他打算這麼做的時候,一場突如其來的意外打破了他的計劃,突然被捲入了一場非洲國家叛亂,本可以安全撤離,卻因無法忘記曾經為軍人的使命,孤身犯險衝回淪陷區,帶領身陷屠殺中的同胞和難民,展開生死逃亡。隨著鬥爭的持續,體內的狼性逐漸復甦,最終孤身闖入戰亂區域,為同胞而戰鬥。");
    	jsonObject5.addProperty("director", "吳京");
    	jsonObject5.addProperty("price", "38");
    	jsonArray.add(jsonObject5);
    	
    	
		for (int i = 0; i < jsonArray.size(); i++) {
			JsonObject jO = jsonArray.get(i).getAsJsonObject();
			IndexResponse indexResponse = client.prepareIndex("film2","dongzuo")
					.setSource(jO.toString(), XContentType.JSON).get();
			System.out.println("索引名稱:"+indexResponse.getIndex());
			System.out.println("型別:"+indexResponse.getType());
			System.out.println("id:"+indexResponse.getId());
			System.out.println("當前索引狀態:"+indexResponse.status());
			
		}
		
	}
	
}