elasticsearch学习——spring整合

1、其实elasticsearch就像是一个数据库一样,index相当于mysql里的数据库database,type相当于mysql的table,field相当于表里面的字段。只不过elasticsearch擅长长文本的存储和查询,mysql擅长处理数据之间的关系。

2、pom文件

<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>

3、创建elasticsearch连接

/**
    	 * 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和端口

4、实例化elasticsearchTemplate

elasticsearchTemplate = new ElasticsearchTemplate(client);

5、创建索引

//判断索引是否存在,不存在则新建一个
        if(!elasticsearchTemplate.indexExists("pan")){
			elasticsearchTemplate.createIndex("pan");
//			elasticsearchTemplate.deleteIndex("pan");//删除索引
		}

6、配置mapping,ES的mapping非常类似于静态语言中的数据类型:声明一个变量为int类型的变量, 以后这个变量都只能存储int类型的数据。同样的, 一个number类型的mapping字段只能存储number类型的数据。同语言的数据类型相比,mapping还有一些其他的含义, mapping不仅告诉ES一个field中是什么类型的值, 它还告诉ES如何索引数据以及数据是否能被搜索到。

两种方式:

6.1、代码式配置

//代码式设置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就完成了

7、为了方便后面有数据查,现在先给出数据

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;  
    }

8、插入或更新多个数据

/**
     * 多个插入或者更新数据
     * @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);
	}

9、插入单个数据

@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);
	}

10、根据id删除数据

/**
     * 根据id删除数据
     * 这里的id指的是_id,即elasticsearch自己自动生成的id
     */
//    @Test
    public void deleteById(){
		elasticsearchTemplate.delete(User.class, "1");
	}

11、一般方式查询数据

/**
     * 使用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);
        
    }

12、组合查询

/**
     * 组合查询
     * 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);
    }

13、模糊查询

/**
     * 模糊查询
     * 它会基于自身规则来进行模糊查询
     */
//    @Test
    public void testFuzzyQuery() {
        QueryBuilder queryBuilder = QueryBuilders.fuzzyQuery("desc", "曹操12");
        searchFunction(queryBuilder);
    }

14、包裹查询

/**
     * 包裹查询
     * 通过设置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);
    }

15、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);
    }

16、父或子文档查询

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

17、根据id查询

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

18、基于内容推荐

/**
     * 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);
    }

19、查询解析字符串

/**
     * 查询解析查询字符串
     */
//    @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);
    }

21、前缀查询

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

22、跨度查询

/**
     * 跨度查询
     */
//    @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", "临江仙"));  

    	
    }

23、通配符查询

/**
     * 通配符查询, 支持 * 
     * 匹配任何字符序列, 包括空
     * 避免* 开始, 会检索大量内容造成效率缓慢
     */
//    @Test
    public void testWildCardQuery() {
        QueryBuilder queryBuilder = QueryBuilders.wildcardQuery("title", "浣*沙");
        searchFunction(queryBuilder);
    }

24、嵌套查询

/**
     * 嵌套查询, 内嵌文档查询
     */
//    @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");
        
    }

25、索引查询,这个没试出来

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

26、获取elasticsearch服务器状态

/**
     * 获取elasticsearch服务器状态
     */
//    @Test
    public void health(){
    	ClusterHealthStatus status = client.admin().cluster().health(new ClusterHealthRequest()).actionGet().getStatus();
    	System.out.println(status.value());
    }

27、前面的searchFunction()方法

private void searchFunction(QueryBuilder queryBuilder) {
		/**
		 * SearchType
		 * 1、query and fetch 
		 * 索引的所有分片(shard)都发出查询请求,各分片返回的时候把元素文档(document)
		 * 和计算后的排名信息一起返回。这种搜索方式是最快的。因为相比下面的几种搜索方式,
		 * 这种查询方法只需要去shard查询一次。但是各个shard返回的结果的数量之和可能是用户要求的size的n倍。
		 * 
		 * 2、query then fetch(默认的搜索方式) 如果你搜索时,没有指定搜索方式,就是使用的这种搜索方式。
		 * 这种搜索方式,大概分两个步骤,第一步,先向所有的shard发出请求,各分片只返回排序和排名相关的信息(注意,不包括文档document),
		 * 然后按照各分片返回的分数进行重新排序和排名,取前size个文档。然后进行第二步,去相关的shard取document。
		 * 这种方式返回的document可能是用户要求的size的n倍,但是由于内部机制的问题query then fetch会比query and fetch占用更多的内存
		 * 
		 * 3、DFS query and fetch 
		 * 这种方式比第一种方式多了一个初始化散发(initial scatter)步骤,有这一步,
		 * 据说可以更精确控制搜索打分和排名。这种方式返回的document与用户要求的size是相等的。
		 * 
		 * 4、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类中

猜你喜欢

转载自my.oschina.net/u/3534905/blog/1631365