elasticsearch學習——spring整合

一、其實elasticsearch就像是一個數據庫同樣,index至關於mysql裏的數據庫database,type至關於mysql的table,field至關於表裏面的字段。只不過elasticsearch擅長長文本的存儲和查詢,mysql擅長處理數據之間的關係。java

二、pom文件mysql

<properties>
		<spring.version>4.2.0.RELEASE</spring.version>
		<findbugs.annotations>2.0.0</findbugs.annotations>
		<checkstyle.maven.plugin>2.11</checkstyle.maven.plugin>
		<pmd.maven.plugin>3.0</pmd.maven.plugin>
		<findbugs.maven.plugin>2.5.3</findbugs.maven.plugin>
		<java.version>1.7</java.version>
	</properties>
	
	
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
			<scope>test</scope>
		</dependency>
		<!-- spring begin -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<!-- spring end -->

		<!-- elasticsearch package -->
		<dependency>
		    <groupId>fr.pilato.spring</groupId>
		    <artifactId>spring-elasticsearch</artifactId>
		    <version>2.2.0</version>
		</dependency>

		<dependency>
		    <groupId>org.elasticsearch</groupId>
		    <artifactId>elasticsearch</artifactId>
		    <version>2.4.0</version>
		</dependency>

		<dependency>
		    <groupId>org.springframework.data</groupId>
		    <artifactId>spring-data-elasticsearch</artifactId>
		    <version>2.0.4.RELEASE</version>
		</dependency>

		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.0.5</version>
		</dependency>

		<!--json-lib -->
		<dependency>
			<groupId>net.sf.json-lib</groupId>
			<artifactId>json-lib</artifactId>
			<version>2.4</version>
			<classifier>jdk15</classifier>
		</dependency>

		<!-- quartz job -->
		<dependency>
			<groupId>org.quartz-scheduler</groupId>
			<artifactId>quartz</artifactId>
			<version>2.2.1</version>
		</dependency>

		<!-- log4j -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.7.5</version>
		</dependency>
	</dependencies>
	
	
  	<build>
		<resources>
			<resource>
				<directory>src/main/resources</directory>
				<includes>
					<include>**/*.*</include>
				</includes>
				<filtering>false</filtering>
			</resource>
			<resource>
				<directory>src/main/java</directory>
				<includes>
					<include>**/*.properties</include>
					<include>**/*.xml</include>
				</includes>
				<filtering>false</filtering>
			</resource>
		</resources>

		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
					<encoding>UTF-8</encoding>
				</configuration>
			</plugin>

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-war-plugin</artifactId>
				<version>2.1-alpha-1</version>
				<configuration>
					<webResources>
						<resource>
							<!-- 元配置文件的目錄,相對於pom.xml文件的路徑 -->
							<directory>src/main/webapp/WEB-INF</directory>
							<!-- 目標路徑 -->
							<targetPath>WEB-INF</targetPath>
						</resource>
					</webResources>
				</configuration>
			</plugin>
		</plugins>
	</build>

 

三、建立elasticsearch鏈接web

/**
    	 * put("client.transport.sniff", true)啓動嗅探功能,客戶端去嗅探整個集羣的狀態,
    	 * 把集羣中其它機器的ip地址加到客戶端中,這樣作的好處是通常你不用手動設置集羣裏所
    	 * 有集羣的ip到鏈接客戶端,它會自動幫你添加,而且自動發現新加入集羣的機器。
    	 */
    	Settings settings = Settings.settingsBuilder().put("cluster.name", "elasticsearch")//設置集羣名字
    			.put("client.transport.sniff", true)//
    			.build();
        client = TransportClient.builder().settings(settings).build()
                 .addTransportAddress(new InetSocketTransportAddress(new InetSocketAddress("127.0.0.1", 9300)));//elasticsearch服務端的ip和端口

四、實例化elasticsearchTemplatespring

elasticsearchTemplate = new ElasticsearchTemplate(client);

五、建立索引sql

//判斷索引是否存在,不存在則新建一個
        if(!elasticsearchTemplate.indexExists("pan")){
			elasticsearchTemplate.createIndex("pan");
//			elasticsearchTemplate.deleteIndex("pan");//刪除索引
		}

六、配置mapping,ES的mapping很是相似於靜態語言中的數據類型:聲明一個變量爲int類型的變量, 之後這個變量都只能存儲int類型的數據。一樣的, 一個number類型的mapping字段只能存儲number類型的數據。同語言的數據類型相比,mapping還有一些其餘的含義, mapping不只告訴ES一個field中是什麼類型的值, 它還告訴ES如何索引數據以及數據是否能被搜索到。數據庫

兩種方式:apache

6.一、代碼式配置json

//代碼式設置mapping(好處:不一樣的索引能夠共用)
        XContentBuilder mapping = null;  
        try {  
            mapping = XContentFactory.jsonBuilder()
            .startObject()
                .startObject("properties")  
                    .startObject("id")
                    	.field("type","String")
                    	.field("index", "not_analyzed")
                    	.field("store", "yes")
                    .endObject() 
                    .startObject("userId")
	                	.field("type","Integer")
	                	.field("index", "not_analyzed")
	                	.field("store", "yes")
	                .endObject()
                    .startObject("title")  
                        .field("type","string")  
                        .field("store", "yes")  
                        //指定index analyzer 爲 ik  
                        .field("analyzer", "ik")  
                        //指定search_analyzer 爲ik_syno
                        .field("searchAnalyzer", "ik")  
                    .endObject() 
                    .startObject("content")
	                    .field("type","string")  
	                    .field("store", "yes")
	                    .field("analyzer", "ik")
	                    .field("searchAnalyzer", "ik")
	                .endObject()
                    .startObject("name")
	                    .field("type","string")  
	                    .field("store", "yes")
	                    .field("analyzer", "ik")
	                    .field("searchAnalyzer", "ik")
	                .endObject()
                    .startObject("desc")
	                    .field("type","string")  
	                    .field("store", "yes")
	                    .field("analyzer", "ik")
	                    .field("searchAnalyzer", "ik")
	                .endObject()
                .endObject()
            .endObject();
        } catch (IOException e) {  
            e.printStackTrace();  
        }
        client.prepareIndex("pan", "shuai").setSource(mapping).execute().actionGet();

6.2註解式配置服務器

首先建立pojo類網絡

/**
 * 
 *@description 
 *@auth panmingshuai
 *@time 2017年12月7日  下午12:31:50
 *
 *
 *
 * @Document註解裏面的幾個屬性,類比mysql的話是這樣: 
 * indexName –> DB 		索引庫的名稱
 * type –> Table 		類型
 * shards  				分片數         		擁有更多的碎片能夠提高索引執行能力,並容許經過機器分發一個大型的索引;
 * replicas  			每一個分區的備份數        擁有更多的副本可以提高搜索執行能力以及集羣能力。
 * refreshInterval   	刷新時間        單位秒
 * indexStoreType		索引文件存儲類型
 *
 *
 */
@Document(indexName = "pan", type = "shuai")
public class User {
	@Field(index = FieldIndex.not_analyzed, store = true)
	private String id;
	
	/**
	 * type  	類型,能夠是boolean,long,double,date,string
	 * index 	是否進行索引,analyzed表示索引,而且對數據進行拆詞,not_analyzed表示索引,可是不進行拆詞,no表示不索引。也就無法對該字段進行搜索。
	 * analyzer	是字段文本的分詞器。默認standard分詞器,另外還有whitespace, simple, or english等。
	 * search_analyzer是搜索詞的分詞器
	 * 設置store爲true,能夠把字段原始值保存,可是索引會更大,須要根據需求使用
	 * String[] ignoreFields() default {};#若是某個字段須要被忽略
	 * 
	 */
	@Field(type = FieldType.Integer, index = FieldIndex.not_analyzed, store= true)
	private Integer userId;
	
	@Field(type = FieldType.String, analyzer = "ik", searchAnalyzer = "ik", store = true)
	private String title;
	
	@Field(type = FieldType.String, analyzer = "ik", searchAnalyzer = "ik", store = true)
	private String content;
	
	@Field(type = FieldType.String, analyzer="ik", searchAnalyzer="ik", store = true)
    private String name;
    
    @Field(type = FieldType.String, index = FieldIndex.not_analyzed, store = true)
    private String desc;

	public User() {
	}

	public User(String id, Integer userId, String title, String content, String name, String desc) {
		super();
		this.id = id;
		this.userId = userId;
		this.title = title;
		this.content = content;
		this.name = name;
		this.desc = desc;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public Integer getUserId() {
		return userId;
	}

	public void setUserId(Integer userId) {
		this.userId = userId;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getDesc() {
		return desc;
	}

	public void setDesc(String desc) {
		this.desc = desc;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", userId=" + userId + ", title=" + title + ", content=" + content + ", name=" + name
				+ ", desc=" + desc + "]";
	}

而後加上

elasticsearchTemplate.putMapping(User.class);

註解式配置mapping就完成了

七、爲了方便後面有數據查,如今先給出數據

private List<String> getTitle() {  
        List<String> list = new ArrayList<>();  
        list.add("《如夢令·常記溪亭日暮》");  
        list.add("abble");  
        list.add("apple");  
        list.add("《永遇樂·落日熔金》");  
        list.add("《如夢令·昨夜雨疏風驟》");  
        list.add("《漁家傲·雪裏已知春信至》");  
        list.add("《點絳脣·蹴[1]罷鞦韆》");  
        list.add("model");  
        list.add("《蝶戀花·淚溼羅衣脂粉滿》");  
        list.add("《蝶戀花 離情》");  
        list.add("《浣溪哈哈沙》");  
        list.add("《浣溪沙》");  
        list.add("《浣溪沙》");  
        list.add("《浣溪沙》");  
        list.add("《浣溪沙》");  
        list.add("《減字木蘭花·賣花擔上》");  
        list.add("《臨江仙·歐陽公做《蝶戀花》");  
        list.add("《臨江仙·庭院深深深幾許》");  
        list.add("《念奴嬌·蕭條庭院》");  
        list.add("《菩薩蠻·風柔日薄春猶早》");  
        list.add("《菩薩蠻·歸鴻聲斷殘雲碧》");  
        list.add("《武陵春·風住塵香花已盡》");  
        list.add("《一剪梅·紅藕香殘玉蕈秋》");  
        list.add("《漁家傲·天接雲濤連曉霧》");  
        list.add("《鷓鴣天·暗淡輕黃體性柔》");  
        list.add("《鷓鴣天·寒日蕭蕭上鎖窗》");  
        list.add("《一剪梅·紅藕香殘玉簟秋》");  
        list.add("《如夢令·常記溪亭日暮》");  
        list.add("《浣溪沙》");  
        list.add("《浣溪沙》");  
        list.add("《浣溪沙》");  
        list.add("《蝶戀花·淚溼羅衣脂粉滿》");  
        list.add("《蝶戀花·暖日晴風初破凍》");  
        list.add("《鷓鴣天·寒日蕭蕭上鎖窗》");  
        list.add("《醉花陰·薄霧濃雲愁永晝》");  
        list.add("《鷓鴣天·暗淡輕黃體性柔》");  
        list.add("《蝶戀花·永夜懨懨歡意少》");  
        list.add("《浣溪沙》");  
        list.add("《浣溪沙》");  
        list.add("《李白如夢令·誰伴明窗獨坐》");  
        return list;  
    }
private List<String> getContent() {  
        List<String> list = new ArrayList<>();  
        list.add("初中 宋·李清照 常記溪亭日暮,沉醉不知歸路,興盡晚回舟,誤入藕花深處。爭渡,爭渡");  
        list.add("重陽節 宋·李清照 薄霧濃雲愁永晝,瑞腦消金獸。佳節又重陽,玉枕紗廚,半夜涼初透。東");  
        list.add("閨怨詩 宋·李清照 尋尋覓覓,冷冷清清,悽悽慘慘慼戚。乍暖還寒時候,最難將息。三杯兩");  
        list.add("元宵節 宋·李清照 落日熔金,暮雲合璧,人在何處。染柳煙濃,吹梅笛怨,春意知幾許。元");  
        list.add("婉約詩 宋·李清照 昨夜雨疏風驟,濃睡不消殘酒,試問卷簾人,卻道海棠依舊。知否,知否");  
        list.add("描寫梅花 宋·李清照 雪裏已知春信至,寒梅點綴瓊枝膩,香臉半開嬌旖旎,當庭際,玉人浴出");  
        list.add(" 宋·李白 蹴罷鞦韆,起來慵整纖纖手。露濃花瘦,薄汗輕衣透。見客入來,襪剗金");  
        list.add("閨怨詩 宋·李清照 寂寞深閨,柔腸一寸愁千縷。惜春春去。幾點催花雨。倚遍闌干,只是無");  
        list.add("婉約詩 宋·李清照 淚溼羅衣脂粉滿。四疊陽關,唱到千千遍。人道山長水又斷。蕭蕭微雨聞");  
        list.add("描寫春天 宋·李清照 暖雨晴風初破凍,柳眼梅腮,已覺春心動。酒意詩情誰與共?淚融殘粉花");  
        list.add("寒食節 宋·李清照 淡蕩春光寒食天,玉爐瀋水嫋殘煙,夢迴山枕隱花鈿。海燕將來人鬥草,");  
        list.add(" 宋·李清照 髻子傷春慵更梳,晚風庭院落梅初,淡雲來往月疏疏,玉鴨薰爐閒瑞腦,");  
        list.add(" 宋·李清照 莫許杯深琥珀濃,未成沉醉意先融。疏鍾已應晚來風。瑞腦香消魂夢斷,");  
        list.add("閨怨詩 宋·李清照 小院閒窗春已深,重簾未卷影沉沉。倚樓無語理瑤琴,遠岫出山催薄暮。");  
        list.add("愛情詩 宋·李清照 繡幕芙蓉一笑開,斜偎寶鴨親香腮,眼波才動被人猜。一面風情深有韻,");  
        list.add("描寫春天 宋·李清照 賣花擔上,買得一枝春欲放。淚染輕勻,猶帶彤霞曉露痕。怕郎猜道,奴");  
        list.add("》 宋·李清照 歐陽公做《蝶戀花》,有「深深深幾許」之句,予酷愛之。用其語做「庭");  
        list.add("描寫梅花 宋·李清照 庭院深深深幾許,雲窗霧閣春遲,爲誰憔悴損芳姿。夜來清夢好,應是發");  
        list.add("寒食節 宋·李清照 蕭條庭院,又斜風細雨,重門須閉。寵柳嬌花寒食近,種種惱人天氣。險");  
        list.add("思鄉詩 宋·李清照 風柔日薄春猶早,夾衫乍著心情好。睡起覺微寒,梅花鬢上殘。故鄉何處");  
        list.add("描寫春天 宋·李清照 歸鴻聲斷殘雲碧,背窗雪落爐煙直。燭底鳳釵明,釵頭人勝輕。角聲催曉");  
        list.add("閨怨詩 宋·李清照 風住塵香花已盡,日晚倦梳頭。物是人非事事休,欲語淚先流。聞說雙溪");  
        list.add(" 宋·李清照 紅藕香殘玉蕈秋,輕解羅裳,獨上蘭舟。雲中誰寄錦書來?雁字回時,月");  
        list.add("豪放詩 宋·曹操5 天接雲濤連曉霧。星河欲轉千帆舞。彷彿夢魂歸帝所。聞天語。殷勤問我");  
        list.add("描寫花 宋·李清照 暗淡輕黃體性柔。情疏跡遠只香留。何必淺碧深紅色,自是花中第一流。");  
        list.add("描寫秋天 宋·李清照 寒日蕭蕭上瑣窗,梧桐應恨夜來霜。酒闌更喜團茶苦,夢斷偏宜瑞腦香。");  
        list.add("閨怨詩 宋·李清照 紅藕香殘玉簟秋。輕解羅裳,獨上蘭舟。雲中誰寄錦書來?雁字回時,月");  
        list.add(" 宋·李清照 常記溪亭日暮。沈醉不知歸路。興盡晚回舟,誤入藕花深處。爭渡。爭渡");  
        list.add(" 宋·李清照 莫許杯深琥珀濃。未成沈醉意先融。已應晚來風。瑞腦香消魂夢斷,");  
        list.add(" 宋·李清照 小院閒窗春色深。重簾未卷影沈沈。倚樓無語理瑤琴。遠岫出山催薄暮,");  
        list.add(" 宋·李清照 淡蕩春光寒食天。玉爐瀋水嫋殘煙。夢迴山枕隱花鈿。海燕將來人鬥草,");  
        list.add(" 宋·李清照 淚溼羅衣脂粉滿。四疊陽關,唱到千千遍。人道山長山又斷。蕭蕭微雨聞");  
        list.add(" 宋·李清照 暖日晴風初破凍。柳眼眉腮,已覺春心動。酒意詩情誰與共。淚融殘粉花");  
        list.add(" 宋·李清照 寒日蕭蕭上鎖窗。梧桐應恨夜來霜。酒闌更喜團茶苦,夢斷偏宜瑞腦香。");  
        list.add(" 宋·李清照 薄霧濃雲愁永晝。瑞腦消金獸。佳節又重陽,玉枕紗廚,半夜涼初透。東");  
        list.add(" 宋·李清照 暗淡輕黃體性柔。情疏跡遠只香留。何必淺碧深紅色,自是花中第一流。");  
        list.add(" 宋·李清照 永夜懨懨歡意少。空夢長安,認取長安道。爲報今年春色好。花光月影宜");  
        list.add(" 宋·李清照 髻子傷春慵更梳。晚風庭院落梅初。淡雲來往月疏疏。玉鴨薰爐閒瑞腦,");  
        list.add(" 宋·李清照 繡面芙蓉一笑開。斜飛寶鴨襯香腮。眼波才動被人猜。一面風情深有韻,");  
        list.add(" 宋·李清照 誰伴明窗獨坐,我共影兒倆個。燈盡欲眠時,影也把人拋躲。無那,無那");  
        return list;  
    }

八、插入或更新多個數據

/**
     * 多個插入或者更新數據
     * @param list
     * @return
     */
//    @Test
    public void insertOrUpdates(){
    	List<User> list = new ArrayList<>();
    	List<String> titles = getTitle();
    	List<String> contents = getContent();
    	for(int i=0; i<titles.size(); i++){
    		User user = new User((i+1)+"", i+10, titles.get(i), contents.get(i), "潘明帥"+i, "曹操"+i);
    		list.add(user);
    	}
    	
    	
		List<IndexQuery> queries = new ArrayList<>();
		for(User user : list){
			//withId 是數據中的_id的指等於user的id,而後既能夠根據user的id的值刪除user
			IndexQuery query = new IndexQueryBuilder().withId(user.getId()).withObject(user).build();
			queries.add(query);
		}
		elasticsearchTemplate.bulkIndex(queries);
	}

九、插入單個數據

@Test
    public void insertOrUpdate(){
    	User user  = new User(45+"", 45+10, "潘明帥", "潘明帥是個大帥哥2", "潘明帥"+45, "曹操"+45);
		IndexQuery query = new IndexQueryBuilder().withId(user.getId()).withObject(user).build();
		elasticsearchTemplate.index(query);
	}

十、根據id刪除數據

/**
     * 根據id刪除數據
     * 這裏的id指的是_id,即elasticsearch本身自動生成的id
     */
//    @Test
    public void deleteById(){
		elasticsearchTemplate.delete(User.class, "1");
	}

十一、通常方式查詢數據

/**
     * 使用QueryBuilder
     * termQuery("key", obj) 徹底匹配
     * termsQuery("key", obj1, obj2..)   一次匹配多個值
     * matchQuery("key", Obj) 單個匹配, field不支持通配符, 前綴具高級特性
     * multiMatchQuery("text", "field1", "field2"..);  匹配多個字段, field有通配符忒行
     * matchAllQuery();         匹配全部文件
     * 
     * 
     * 默認的standard analyzer分詞規則:
     * 去掉大部分標點符號,並以此分割原詞爲多個詞,把分分割後的詞轉爲小寫放入token組中。
     * 對於not-analyzed的詞,直接把原詞放入token組中。
     * matchQuery的機制是:先檢查字段類型是不是analyzed,若是是,則將用來查詢的詞例以下面的「寒食」先分詞,再去去匹配token;若是不是,則直接去匹配token。
     * termQuery的機制是:則將用來查詢的詞例以下面的「寒食節」不分詞,直接去匹配token。
     */
//    @Test
    public void testQueryBuilder() {
    	QueryBuilder queryBuilder = QueryBuilders.termQuery("name", "潘明帥6");
//    	QueryBuilder queryBuilder = QueryBuilders.termsQuery("content", "寒食節", "春心");
//    	QueryBuilder queryBuilder = QueryBuilders.matchQuery("content", "寒食節");
//    	QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery("李清照", "desc", "content");
//    	QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
    	searchFunction(queryBuilder);
        
    }

十二、組合查詢

/**
     * 組合查詢
     * must(QueryBuilders) :   AND
     * mustNot(QueryBuilders): NOT
     * should:                  : OR
     */
//    @Test
    public void testQueryBuilder2() {
        QueryBuilder queryBuilder = QueryBuilders.boolQuery()
            .must(QueryBuilders.matchQuery("name", "潘明帥"))
            .mustNot(QueryBuilders.termQuery("title", "菩薩蠻"))
            .should(QueryBuilders.termQuery("content", "思鄉"));
        searchFunction(queryBuilder);
    }

1三、模糊查詢

/**
     * 模糊查詢
     * 它會基於自身規則來進行模糊查詢
     */
//    @Test
    public void testFuzzyQuery() {
        QueryBuilder queryBuilder = QueryBuilders.fuzzyQuery("desc", "曹操12");
        searchFunction(queryBuilder);
    }

1四、包裹查詢

/**
     * 包裹查詢
     * 經過設置boost來提升當前查詢的權重(官方文檔說返回的score和boost相等), 提升該查詢的相關度
     * 應用場景(來源網絡): 好比匹配酒店設備:多個term 泳池,花園,wifi 好比咱們要將泳池的的分值放大,
     * 則將泳池的term經過該方式包一下,並設置一個你認爲合理的權重,提升泳池在酒店匹配過程的佔比。
     */
//    @Test
    public void testConstantScoreQuery() {
        QueryBuilder queryBuilder = QueryBuilders.boolQuery().should(QueryBuilders.constantScoreQuery(QueryBuilders.termQuery("title", "念奴嬌")).boost(2.0f))
        		.should(QueryBuilders.constantScoreQuery(QueryBuilders.termQuery("content", "李清照")).boost(2.0f));
        searchFunction(queryBuilder);
    }

1五、dismax查詢

/**
     * disMax查詢
     * 對子查詢的結果作union, 
     * 沒個文檔的分數是 子查詢中相同文檔的得分最大值。 例: 北京大飯店 
     * 酒索引得分 0; 店 得分 1; 大得分1.1 最後的結果是 北京大飯店相關度得分1.1
     */
//    @Test
    public void testDisMaxQuery() {
        QueryBuilder queryBuilder = QueryBuilders.disMaxQuery()
            .add(QueryBuilders.termQuery("title", "念奴嬌"))  // 查詢條件
            .add(QueryBuilders.termQuery("content", "李清照"))
            .boost(1.3f)
            .tieBreaker(0.7f);
        searchFunction(queryBuilder);
    }

1六、父或子文檔查詢

/**
     * 父子文檔查詢
     */
//    @Test
    public void testChildQuery() {
        QueryBuilder queryBuilder = QueryBuilders.hasChildQuery("sonDoc", QueryBuilders.termQuery("name", "vini"));
        searchFunction(queryBuilder);
    }

1七、根據id查詢

/**
     * 根據id查詢
     */
//    @Test
    public void testIdsQuery() {
        QueryBuilder queryBuilder = QueryBuilders.idsQuery().ids("1","2");
        searchFunction(queryBuilder);
    }

1八、基於內容推薦

/**
     * moreLikeThisQuery: 實現基於內容推薦, 支持實現一句話類似文章查詢
     * percent_terms_to_match:匹配項(term)的百分比,默認是0.3
     * min_term_freq:一篇文檔中一個詞語至少出現次數,小於這個值的詞將被忽略,默認是2
     * max_query_terms:一條查詢語句中容許最多查詢詞語的個數,默認是25
     * stop_words:設置中止詞,匹配時會忽略中止詞
     * min_doc_freq:一個詞語最少在多少篇文檔中出現,小於這個值的詞會將被忽略,默認是無限制
     * max_doc_freq:一個詞語最多在多少篇文檔中出現,大於這個值的詞會將被忽略,默認是無限制
     * min_word_len:最小的詞語長度,默認是0
     * max_word_len:最多的詞語長度,默認無限制
     * boost_terms:設置詞語權重,默認是1
     * boost:設置查詢權重,默認是1
     * analyzer:設置使用的分詞器,默認是使用該字段指定的分詞器
     */
//    @Test
    public void testMoreLikeThisQuery() {
        QueryBuilder queryBuilder = QueryBuilders.moreLikeThisQuery("content")
                            .like("閨怨詩 宋·李清照").minTermFreq(1);
//                             minTermFreq(1)        //最少出現的次數
//                            .maxQueryTerms(12);        // 最多容許查詢的詞語
        searchFunction(queryBuilder);
    }

1九、查詢解析字符串

/**
     * 查詢解析查詢字符串
     */
//    @Test
    public void testQueryString() {
        QueryBuilder queryBuilder = QueryBuilders.queryStringQuery("\""+"李白"+"\"");
        searchFunction(queryBuilder);
    }

20、範圍查詢

/**
     * 範圍內查詢
     */
//    @Test
    public void testRangeQuery() {
    	//數字範圍
//        QueryBuilder queryBuilder = QueryBuilders.rangeQuery("userId").gt(20).lt(30)
//            .includeLower(true)     // 包含上界
//            .includeUpper(true);      // 包含下屆
    	//字符串範圍
        QueryBuilder queryBuilder = QueryBuilders.rangeQuery("title").from("ab").to("aq")
                .includeLower(true)     // 包含上界
                .includeUpper(true);	// 包含下屆
        searchFunction(queryBuilder);
    }

2一、前綴查詢

/**
     * 前綴查詢
     */
//    @Test
    public void testPrefixQuery() {
        QueryBuilder queryBuilder = QueryBuilders.prefixQuery("title", "mo");
        searchFunction(queryBuilder);
    }

2二、跨度查詢

/**
     * 跨度查詢
     */
//    @Test
    public void testSpanQueries() {
    	/**
    	 * 這個查詢若是單獨使用,效果跟term查詢差很少,可是通常仍是用於其餘的span查詢的子查詢。
    	 */
    	QueryBuilder queryBuilder0 = QueryBuilders.spanTermQuery("title", "mo");
    	
    	/**
    	 * 這個查詢用於肯定一個單詞相對於起始位置的偏移位置,舉個例子:
    	 * 若是一個文檔字段的內容是:「hello,my name is tom」,咱們要檢索tom,那麼它的span_first最小應該是5,不然就查找不到。
    	 * 使用的時候,只是比span_term多了一個end界定而已
    	 */
    	QueryBuilder queryBuilder1 = QueryBuilders.spanFirstQuery(QueryBuilders.spanTermQuery("title", "mo"), 30000);// Max查詢範圍的結束位置  
      
    	/**
    	 * 這個查詢主要用於肯定幾個span_term之間的距離,一般用於檢索某些相鄰的單詞,避免在全局跨字段檢索而干擾最終的結果。
    	 * 查詢主要由兩部分組成,一部分是嵌套的子span查詢,另外一部分就是他們之間的最大的跨度
    	 */
    	QueryBuilder queryBuilder2 = QueryBuilders.spanNearQuery()  
    			.clause(QueryBuilders.spanTermQuery("title", "mo")) // 或者子查詢
                .clause(QueryBuilders.spanTermQuery("title", "浣溪沙"))  
                .clause(QueryBuilders.spanTermQuery("title", "臨江仙"))  
                .slop(30000)                                               // 跨度
                .inOrder(false)  
                .collectPayloads(false);  
  
        /**
         * 這個查詢相對於span_or來講,就是排除的意思。不過它內部有幾個屬性,
         * include用於定義包含的span查詢;exclude用於定義排除的span查詢
         */
    	QueryBuilder queryBuilder3 = QueryBuilders.spanNotQuery()  
    			.include(QueryBuilders.spanTermQuery("title", "mo"))  
    			.exclude(QueryBuilders.spanTermQuery("title", "浣溪沙"));  
  
        /**
         * 這個查詢會嵌套一些子查詢,子查詢之間的邏輯關係爲 或
         */
    	QueryBuilder queryBuilder4 = QueryBuilders.spanOrQuery()  
    			.clause(QueryBuilders.spanTermQuery("title", "mo"))  
    			.clause(QueryBuilders.spanTermQuery("title", "浣溪沙"))  
    			.clause(QueryBuilders.spanTermQuery("title", "臨江仙"));  

    	
    }

2三、通配符查詢

/**
     * 通配符查詢, 支持 * 
     * 匹配任何字符序列, 包括空
     * 避免* 開始, 會檢索大量內容形成效率緩慢
     */
//    @Test
    public void testWildCardQuery() {
        QueryBuilder queryBuilder = QueryBuilders.wildcardQuery("title", "浣*沙");
        searchFunction(queryBuilder);
    }

2四、嵌套查詢

/**
     * 嵌套查詢, 內嵌文檔查詢
     */
//    @Test
    public void testNestedQuery() {
    	QueryBuilder queryBuilder = QueryBuilders.nestedQuery("location", 
    			QueryBuilders.boolQuery().must(
    					QueryBuilders.matchQuery("location.lat", 0.962590433140581))
    					.must(QueryBuilders.rangeQuery("location.lon").gt(0.000).lt(36.0000)))
    			.scoreMode("total");
        
    }

2五、索引查詢,這個沒試出來

//    @Test
    public void testIndicesQueryBuilder () {
        QueryBuilder queryBuilder = QueryBuilders.indicesQuery(QueryBuilders.termQuery("desc", "曹操45"), "heros", "pan");
        searchFunction(queryBuilder);
        
    }

2六、獲取elasticsearch服務器狀態

/**
     * 獲取elasticsearch服務器狀態
     */
//    @Test
    public void health(){
    	ClusterHealthStatus status = client.admin().cluster().health(new ClusterHealthRequest()).actionGet().getStatus();
    	System.out.println(status.value());
    }

2七、前面的searchFunction()方法

private void searchFunction(QueryBuilder queryBuilder) {
		/**
		 * SearchType
		 * 一、query and fetch 
		 * 索引的全部分片(shard)都發出查詢請求,各分片返回的時候把元素文檔(document)
		 * 和計算後的排名信息一塊兒返回。這種搜索方式是最快的。由於相比下面的幾種搜索方式,
		 * 這種查詢方法只須要去shard查詢一次。可是各個shard返回的結果的數量之和多是用戶要求的size的n倍。
		 * 
		 * 二、query then fetch(默認的搜索方式) 若是你搜索時,沒有指定搜索方式,就是使用的這種搜索方式。
		 * 這種搜索方式,大概分兩個步驟,第一步,先向全部的shard發出請求,各分片只返回排序和排名相關的信息(注意,不包括文檔document),
		 * 而後按照各分片返回的分數進行從新排序和排名,取前size個文檔。而後進行第二步,去相關的shard取document。
		 * 這種方式返回的document多是用戶要求的size的n倍,可是因爲內部機制的問題query then fetch會比query and fetch佔用更多的內存
		 * 
		 * 三、DFS query and fetch 
		 * 這種方式比第一種方式多了一個初始化散發(initial scatter)步驟,有這一步,
		 * 聽說能夠更精確控制搜索打分和排名。這種方式返回的document與用戶要求的size是相等的。
		 * 
		 * 四、DFS query then fetch 比第2種方式多了一個初始化散發(initial scatter)步驟。
		 * 這種方式返回的document與用戶要求的size是相等的。
		 * 
		 * DSF表示初始化散發,從es的官方網站咱們能夠指定,初始化散發其實就是在進行真正的查詢以前,
		 * 先把各個分片的詞頻率和文檔頻率收集一下,而後進行詞搜索的時候,
		 * 各分片依據全局的詞頻率和文檔頻率進行搜索和排名。顯然若是使用DFS_QUERY_THEN_FETCH
		 * 這種查詢方式,效率是最低的,由於一個搜索,可能要請求3次分片。但,使用DFS方法,搜索精度應該是最高的。
		 * 
		 * 總結一下,從性能考慮QUERY_AND_FETCH是最快的,DFS_QUERY_THEN_FETCH是最慢的。
		 * 從搜索的準確度來講,DFS要比非DFS的準確度更高。
		 * 
		 * 
		 * setExplain爲true表示根據數據相關度排序,和關鍵字匹配最高的排在前面
		 * 
		 * addSort添加排序方式
		 */
		SearchResponse response = client.prepareSearch("pan").setTypes("shuai")
                .setSearchType(SearchType.DFS_QUERY_THEN_FETCH).setExplain(true)
                .setQuery(queryBuilder)
                .addSort("id", SortOrder.ASC)
                .addHighlightedField("title").setHighlighterPreTags("<h1>").setHighlighterPostTags("</h1>")//高亮的字段必須是査取出的字段,即這個字段被明確在queerybuilder中査取
                .setSize(100).execute().actionGet();
        
		for (SearchHit hit : response.getHits()) {
            System.out.println(hit.getSource());

            if(hit.getHighlightFields() != null && hit.getHighlightFields().size() != 0){
            	Text[] texts = hit.getHighlightFields().get("title").getFragments();
    			for(Text text : texts){
    				System.out.println(text.string() + ",");
    			}
            }
            
        }
    }

上面的代碼除了User類須要新建以外,其餘的能夠放到一個test類中

相關文章
相關標籤/搜索