分布式搜索 Elasticsearch —— QueryBuilders

一、QueryBuilders.matchAllQuery

源代码解释如下:

/**
 * A query that match on all documents
 */
public static MatchAllQueryBuilder matchAllQuery(){
 return new MatchAllQueryBuilder();
}

即用于匹配索要的 Document 的 Query, 以下是 matchAllQuery 的示例及常用场景:


package com.gsoft.gcrsearch.util;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import junit.framework.Assert;

import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.Client;
import org.elasticsearch.index.query.FilterBuilders;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.node.Node;
import org.elasticsearch.node.NodeBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.gsoft.gcrsearch.entity.Person;


public class QueryBuildersTest {

	private static Client client;

	private static ObjectMapper mapper;

	@BeforeClass
	public static void beforeClass() {
		System.out.println("==============执行beforeClass()");
		NodeBuilder builder = NodeBuilder.nodeBuilder();
		String clusterName = PropertyManager.getContextProperty("cluster.name");
		builder.clusterName(clusterName);
		Node node = builder.node();
		client = node.client();
		mapper = new ObjectMapper();
	}

	@Before
	public void beforeMethod() throws Exception {

		System.out.println("==============执行beforeMethod()");

		List<Person> persons = new ArrayList<Person>();

		List<IndexRequest> requests = new ArrayList<IndexRequest>();

		for (int i = 0; i < 10; i++) {
			Person person = new Person();
			person.setAge(20 + i);
			person.setId(UUID.randomUUID().toString());
			person.setIsStudent(true);
			person.setName("小别克听老别克讲别克的故事" + i);
			person.setSex("男");
			persons.add(person);

			String index = "user"; // 相当于数据库名
			String type = "tb_person" + i; // 相当于表名

			String json = mapper.writeValueAsString(person);

			IndexRequest request = client
					.prepareIndex(index, type, person.getId()).setSource(json)
					.request();

			requests.add(request);
		}

		BulkRequestBuilder bulkRequest = client.prepareBulk();

		for (IndexRequest request : requests) {
			bulkRequest.add(request);
		}

		BulkResponse bulkResponse = bulkRequest.execute().actionGet();
		if (bulkResponse.hasFailures()) {
			Assert.fail("批量创建索引错误!");
		}
	}

	/**
	 * 常用场景一:匹配所有项
	 * @throws Exception
	 */
	@Test
	public void matchAllQuery() throws Exception {

		QueryBuilder builder = QueryBuilders.matchAllQuery();

		SearchResponse response = client
				.prepareSearch("user")
				.setTypes("tb_person0", "tb_person1", "tb_person2",
						"tb_person3", "tb_person4")
				.setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
				.setQuery(builder) // Query
				.setFilter(FilterBuilders.rangeFilter("age").from(20).to(22)) // Filter
				.setFrom(0).setSize(60).setExplain(true).execute().actionGet();
		SearchHits hits = response.getHits();
		for (SearchHit hit : hits) {
			String json = hit.getSourceAsString();

			Person newPerson = mapper.readValue(json, Person.class);
			System.out.println("name\t\t" + newPerson.getName());
			System.out.println("sex\t\t" + newPerson.getSex());
			System.out.println("age\t\t" + newPerson.getAge());
			System.out.println("isStudent\t\t" + newPerson.getIsStudent());
		}
	}

	/**
	 * 常用场景二:查询某些(个)Index、某些(个)Type下的记录总量
	 * @throws Exception
	 */
	@Test
	public void matchAllQueryForCount() throws Exception {
		QueryBuilder builder = QueryBuilders.matchAllQuery();
		long count = client.prepareCount("user")
				.setQuery(builder)
				.setTypes("tb_person0", "tb_person1", "tb_person2",
						"tb_person3", "tb_person4").execute().actionGet()
				.count();
		Assert.assertTrue(count >= 3);
	}

}

二、QueryBuilders.matchQuery

ES 源代码中 对 matchQuery 的描述如下所示:

/**
 * Create a match query with type "BOOLEAN" for the provided field name and text
 *
 * @param name The field name
 * @param text The query text (to be analyzed)
 */
public static MatchQueryBuilder matchQuery(String name,Object text){
  return new MatchQueryBuilder(name,text).type(MatchQueryBuilder.Type.BOOLEAN);
}

总的来说,matchQuery 能够使用某一 field 的值对Document进行查询。


package com.geloin.esample.util;

import java.util.UUID;

import junit.framework.Assert;

import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.junit.Test;

import com.geloin.esample.BaseTest;
import com.geloin.esample.entity.Person;

public class MatchQueryTest extends BaseTest {

	@Test
	public void matchQuery() {
		try {
			String name = "name";
			String text = "别克";
			BulkRequestBuilder requestBuilder = client.prepareBulk();
			// 创建索引
			for (int i = 0; i < 10; i++) {
				Person p = new Person();
				p.setAge(20 + i);
				p.setId(UUID.randomUUID().toString());
				p.setIsStudent(true);
				p.setName("小别克听老别克讲别克的故事" + i);
				p.setSex("男");

				String source = ElasticSearchUtil.BeanToJson(p);
				IndexRequest request = client
						.prepareIndex(index, type, p.getId()).setSource(source)
						.request();

				requestBuilder.add(request);
			}
			BulkResponse response = requestBuilder.execute().actionGet();
			if (response.hasFailures()) {
				Assert.fail("创建索引失败!");
			}

			// 检索
			QueryBuilder qb = QueryBuilders.matchQuery(name, text);
			SearchResponse searchResponse = client.prepareSearch(index)
					.setTypes(type).setQuery(qb).setFrom(0).setSize(12)
					.execute().actionGet();

			SearchHits hits = searchResponse.getHits();
			if (null == hits || hits.totalHits() == 0) {
				log.error("没有查询到任何结果!");
				return;
			} else {
				for (SearchHit hit : hits) {
					String json = hit.getSourceAsString();

					Person newPerson = mapper.readValue(json, Person.class);
					System.out.println("name\t\t" + newPerson.getName());
					System.out.println("sex\t\t" + newPerson.getSex());
					System.out.println("age\t\t" + newPerson.getAge());
					System.out.println("isStudent\t\t"
							+ newPerson.getIsStudent());
				}
			}
			
			Thread.sleep(1000000);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

 

三、QueryBuilders.termQuery

ES对 termQuery 描述如下:

    /**
     * A Query that matches documents containing a term.
     *
     * @param name  The name of the field
     * @param value The value of the term
     */
    public static TermQueryBuilder termQuery(String name, String value) {
        return new TermQueryBuilder(name, value);
    }

termQuery 的Value 有以下情况:

  1. 若 value 为汉字,则大部分情况下,只能为一个汉字;
  2. 若 value 为英文,则是一个单词;

termQuery代码如下

package com.geloin.esample.util;

import java.util.UUID;

import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.junit.Test;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.geloin.esample.BaseTest;
import com.geloin.esample.entity.Person;



public class TermQueryTest extends BaseTest {

	@Test
	public void termQuery() {
		String index = "user";
		String type = "tb_person";
		try {
			// 创建索引
			Person p = new Person();
			p.setId(UUID.randomUUID().toString());
			p.setAge(20);
			p.setIsStudent(false);
			p.setSex("男");
			p.setName("别克");

			ObjectMapper mapper = new ObjectMapper();
			String source = mapper.writeValueAsString(p);

			client.prepareIndex(index, type, p.getId()).setSource(source)
					.execute().actionGet();

			// 查询
			QueryBuilder qb = QueryBuilders.termQuery("name", "别");

			SearchResponse sResponse = client.prepareSearch(index)
					.setTypes(type).setQuery(qb).setFrom(0).setSize(12)
					.execute().actionGet();
			SearchHits hits = sResponse.getHits();

			if (null != hits && hits.totalHits() > 0) {
				for (SearchHit hit : hits) {
					String json = hit.getSourceAsString();
					Person newPerson = mapper.readValue(json, Person.class);
					System.out.println("name\t\t" + newPerson.getName());
					System.out.println("sex\t\t" + newPerson.getSex());
					System.out.println("age\t\t" + newPerson.getAge());
					System.out.println("isStudent\t\t"
							+ newPerson.getIsStudent());
				}
			} else {
				log.info("没有查询到任何结果!");
			}

			// 防止出现:远程主机强迫关闭了一个现有的连接
			Thread.sleep(100000);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}
}

 

三、QueryBuilders.multiMatchQuery

 ES 对 multiMatchQuery 的描述如下:

/***
 * creates a match query with type "BOOLEAN" for the provided field name and text.
 * 
 *
 * @param fieldNames The field names
 * @param text       The query text ( to be analyzed )
 * 
 */
 public static MultiMatchQueryBuilder multiMatchQuery(Object text,String... fieldNames){
   return new MultiMatchQueryBuilder(text,fieldNames); // BOOLEAN is the default;
 }

相当于 matchQuery , multiMatchQuery 针对的是多个 field 也就是说当 multiMatchQuery 中,fieldNames 参数只有一个的时候,其作用与 matchQuery 相当;而当fieldNames有多个参数时候,如 field1,field2,那么查询结果中,要么field1 包含text 要么field2中包含text;

示例代码如下:
 

package com.geloin.esample.util;

import java.util.UUID;

import junit.framework.Assert;

import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.junit.Test;

import com.geloin.esample.BaseTest;
import com.geloin.esample.entity.Person;


public class MultiMatchQueryTest extends BaseTest {

	@Test
	public void multiMatchQueryTest() {
		try {
			// 创建索引
			BulkRequestBuilder builder = client.prepareBulk();

			for (int i = 0; i < 5; i++) {
				Person p = new Person();
				p.setId(UUID.randomUUID().toString());
				p.setAge(20);
				p.setIsStudent(false);
				p.setSex("男");
				p.setName("小别克听老别克讲别克的故事");

				String source = ElasticSearchUtil.BeanToJson(p);

				IndexRequest request = client
						.prepareIndex(index, type, p.getId()).setSource(source)
						.request();

				builder.add(request);
			}

			for (int i = 0; i < 5; i++) {
				Person p = new Person();
				p.setId(UUID.randomUUID().toString());
				p.setAge(20);
				p.setIsStudent(false);
				p.setSex("男装别克");
				p.setName("名字里面没有查询的关键字");

				String source = ElasticSearchUtil.BeanToJson(p);

				IndexRequest request = client
						.prepareIndex(index, type, p.getId()).setSource(source)
						.request();

				builder.add(request);
			}

			BulkResponse response = builder.execute().actionGet();

			if (response.hasFailures()) {
				Assert.fail("创建索引失败!");
			}

			String text = "别克";
			// 检索
			QueryBuilder qb = QueryBuilders
					.multiMatchQuery(text, "name", "sex");
			SearchResponse sResponse = client.prepareSearch(index)
					.setTypes(type).setQuery(qb).setFrom(0).setSize(12)
					.execute().actionGet();

			SearchHits hits = sResponse.getHits();
			if (null != hits && hits.totalHits() > 0) {
				for (SearchHit hit : hits) {
					String json = hit.getSourceAsString();
					Person newPerson = mapper.readValue(json, Person.class);
					System.out.println("name\t\t" + newPerson.getName());
					System.out.println("sex\t\t" + newPerson.getSex());
					System.out.println("age\t\t" + newPerson.getAge());
					System.out.println("isStudent\t\t"
							+ newPerson.getIsStudent());
				}
			} else {
				log.info("没有查询到任何结果!");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

 

四、QueryBuilders.matchPhraseQuery

ES 源代码matchPhraseQuery 的描述如下:

    /**
     * Creates a text query with type "PHRASE" for the provided field name and text.
     *
     * @param name The field name.
     * @param text The query text (to be analyzed).
     */
    public static MatchQueryBuilder matchPhraseQuery(String name, Object text) {
        return new MatchQueryBuilder(name, text).type(MatchQueryBuilder.Type.PHRASE);
    }
package com.geloin.esample.util;

import java.util.UUID;

import junit.framework.Assert;

import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.junit.Test;

import com.geloin.esample.BaseTest;
import com.geloin.esample.entity.Person;


public class MatchPhraseQueryTest extends BaseTest {

	@Test
	public void matchPhraseQuery() {
		try {
			// 创建索引
			BulkRequestBuilder builder = client.prepareBulk();

			for (int i = 0; i < 5; i++) {
				Person p = new Person();
				p.setId(UUID.randomUUID().toString());
				p.setAge(20);
				p.setIsStudent(false);
				p.setSex("男");
				p.setName("小别克听老别克讲别克的故事");

				String source = ElasticSearchUtil.BeanToJson(p);

				IndexRequest request = client.prepareIndex().setIndex(index)
						.setType(type).setId(p.getId()).setSource(source)
						.request();

				builder.add(request);
			}

			BulkResponse bResponse = builder.execute().actionGet();
			if (bResponse.hasFailures()) {
				Assert.fail("创建索引出错!");
			}

			// 检索
			QueryBuilder qb = QueryBuilders.matchPhraseQuery("name", "小别克老");
			SearchResponse searchResponse = client.prepareSearch(index)
					.setTypes(type).setQuery(qb).setFrom(0).setSize(12)
					.execute().actionGet();

			SearchHits hits = searchResponse.getHits();
			if (null == hits || hits.totalHits() == 0) {
				log.error("使用\"小别克老\"没有查询到任何结果!");
			} else {
				for (SearchHit hit : hits) {
					String json = hit.getSourceAsString();

					Person newPerson = mapper.readValue(json, Person.class);
					System.out.println("name\t\t" + newPerson.getName());
					System.out.println("sex\t\t" + newPerson.getSex());
					System.out.println("age\t\t" + newPerson.getAge());
					System.out.println("isStudent\t\t"
							+ newPerson.getIsStudent());
				}
			}
			
			// 检索
			QueryBuilder qb1 = QueryBuilders.matchPhraseQuery("name", "小别克听");
			SearchResponse searchResponse1 = client.prepareSearch(index)
					.setTypes(type).setQuery(qb1).setFrom(0).setSize(12)
					.execute().actionGet();
			
			SearchHits hits1 = searchResponse1.getHits();
			if (null == hits1 || hits1.totalHits() == 0) {
				log.error("使用\"小别克听\"没有查询到任何结果!");
				return;
			} else {
				for (SearchHit hit : hits1) {
					String json = hit.getSourceAsString();
					
					Person newPerson = mapper.readValue(json, Person.class);
					System.out.println("name\t\t" + newPerson.getName());
					System.out.println("sex\t\t" + newPerson.getSex());
					System.out.println("age\t\t" + newPerson.getAge());
					System.out.println("isStudent\t\t"
							+ newPerson.getIsStudent());
				}
			}

			Thread.sleep(1000000);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

你会发现,使用 "小别克老" 没有查询出任何结果,而 使用 "小别克听" 则查询出我们需要的结果,

这便是 matchPhraseQuery 和 matchQuery 等区别,在使用 matchQuery等时,即使你传入的是 "小别克老",在执行查询的时候,"小别克老"会被分词器粉刺 ,例如  paoding 解析成 "小别/别克/老" ,而使用 matchPhraseQuery 时候,"小别克老"并不会被分词器分词,而直接以一个短语的形式查询,而如果你在创建索引所使用的 field 的 value 中没有这么一个短语( 顺序无差,且连接在一起 ),那么将查询不出任何结果。

五、QueryBuilders.matchPhrasePrefixQuery

ES 源代码中对 matchPhrasePrefixQuery 的描述如下:

    /**
     * Creates a match query with type "PHRASE_PREFIX" for the provided field name and text.
     *
     * @param name The field name.
     * @param text The query text (to be analyzed).
     */
    public static MatchQueryBuilder matchPhrasePrefixQuery(String name, Object text) {
        return new MatchQueryBuilder(name, text).type(MatchQueryBuilder.Type.PHRASE_PREFIX);
    }

如果你调用 matchPhrasePrefixQuery 时候,text为中文,那么,很大可能是一种状况:你会发现,matchPhrasePrefixQuery 和 matchPhraseQuery 没有任何差别,而当 text为英文时,差别就显现出来了:matchPhraseQuery 的 text 是一个英文单词,而matchPhrasePrefixQuery 的 text 则 无 这一约束,你可以从一个英文单词中抽几个连接在一起的字母进行查询。

package com.gsoft.gsearch.util;

import java.util.UUID;

import junit.framework.Assert;

import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.junit.Test;

import com.gsoft.gsearch.BaseTest;
import com.gsoft.gsearch.entity.Person;

/**
 * 以短语形式查询,查询时关键字不会被分词,而是直接以一个字符串的形式查询
 * 
 */
public class MatchPhrasePrefixQueryTest extends BaseTest {
	
	@Test
	public void matchPhrasePrefixQuery() {
		try {
			
			// 创建索引
			BulkRequestBuilder builder = client.prepareBulk();

			for (int i = 0; i < 2; i++) {
				Person p = new Person();
				p.setId(UUID.randomUUID().toString());
				p.setAge(20);
				p.setIsStudent(false);
				p.setSex("男");
				p.setName("Zhangsan wang");

				String source = ElasticSearchUtil.BeanToJson(p);

				IndexRequest request = client.prepareIndex().setIndex(index)
						.setType(type).setId(p.getId()).setSource(source)
						.request();

				builder.add(request);
			}

			BulkResponse bResponse = builder.execute().actionGet();
			if (bResponse.hasFailures()) {
				Assert.fail("创建索引出错!");
			}

			// 检索
			QueryBuilder qb = QueryBuilders.matchPhraseQuery("name", "wa");
			
			SearchResponse searchResponse = client.prepareSearch(index)
					.setTypes(type).setQuery(qb).setFrom(0).setSize(12)
					.execute().actionGet();

			SearchHits hits = searchResponse.getHits();
			if (null == hits || hits.totalHits() == 0) {
				log.error("使用matchPhraseQuery(\"name\", \"<span style="font-size:14px;">wa</span>\")没有查询到任何结果!");
			} else {
				for (SearchHit hit : hits) {
					String json = hit.getSourceAsString();

					Person newPerson = mapper.readValue(json, Person.class);
					System.out.println("name\t\t" + newPerson.getName());
					System.out.println("sex\t\t" + newPerson.getSex());
					System.out.println("age\t\t" + newPerson.getAge());
					System.out.println("isStudent\t\t"
							+ newPerson.getIsStudent());
				}
			}
			
			System.out.println("===================================================");

			// 检索
			QueryBuilder qb1 = QueryBuilders.matchPhrasePrefixQuery("name", "wa");
			
			SearchResponse searchResponse1 = client.prepareSearch(index)
					.setTypes(type).setQuery(qb1).setFrom(0).setSize(20)
					.execute().actionGet();

			SearchHits hits1 = searchResponse1.getHits();
			
			
			if (null == hits1 || hits1.totalHits() == 0) {
				log.error("使用matchPhrasePrefixQuery(\"name\", \"wa\")没有查询到任何结果!");
				return;
			} else {
				for (SearchHit hit : hits1) {
					String json = hit.getSourceAsString();

					Person newPerson = mapper.readValue(json, Person.class);
					System.out.println("name\t\t" + newPerson.getName());
					System.out.println("sex\t\t" + newPerson.getSex());
					System.out.println("age\t\t" + newPerson.getAge());
					System.out.println("isStudent\t\t"
							+ newPerson.getIsStudent());
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (null != client) {
				client.close();
			}
			if (null != node) {
				node.close();
			}
		}
	}
}

你会发现,使用 matchPhraseQuery 并未查询出结果,而 matchPhrasePrefixQuery 查询出的,则是我们希望的结果。

 

六、QueryBuilders.idsQuery

ES源码中对 idsQuery的描述如下

    /**
     * Constructs a query that will match only specific ids within types.
     *
     * @param types The mapping/doc type
     */
    public static IdsQueryBuilder idsQuery(@Nullable String... types) {
        return new IdsQueryBuilder(types);
    }

及指定type 和 id 进行查询。

示例代码:

package com.gsoft.gsearch.util;

import junit.framework.Assert;

import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.junit.Test;

import com.gsoft.gsearch.BaseTest;
import com.gsoft.gsearch.entity.Person;

public class IdsQueryTest extends BaseTest {
	@Test
	public void idsQuery() {
		try {
			
			String id1 = "udisjkdfd";
			String id2 = "ewdsfdsfe";

			BulkRequestBuilder builder = client.prepareBulk();
			// 创建索引
			Person p = new Person();
			p.setAge(20);
			p.setId(id1);
			p.setIsStudent(true);
			p.setName("张三的故事" + Math.random());
			p.setSex("男");

			String source = ElasticSearchUtil.BeanToJson(p);

			IndexRequest request = client.prepareIndex(index, type, p.getId())
					.setSource(source).request();

			builder.add(request);

			Person p2 = new Person();
			p2.setAge(20);
			p2.setId(id2);
			p2.setIsStudent(true);
			p2.setName("小李四讲的李四的故事" + Math.random());
			p2.setSex("男");

			String source2 = ElasticSearchUtil.BeanToJson(p2);

			IndexRequest request2 = client
					.prepareIndex(index, type, p2.getId()).setSource(source2)
					.request();

			builder.add(request2);

			BulkResponse response = builder.execute().actionGet();
			if (response.hasFailures()) {
				Assert.fail("创建索引失败!");
			}

			// 检索
			QueryBuilder qb = QueryBuilders.idsQuery(type).ids(id1, id2);

			SearchResponse sr = client.prepareSearch(index).setTypes(type)
					.setQuery(qb).setFrom(0).setSize(12).execute().actionGet();

			SearchHits hits = sr.getHits();

			if (null != hits && hits.totalHits() > 0) {
				for (SearchHit hit : hits) {
					String json = hit.getSourceAsString();

					Person newPerson = mapper.readValue(json, Person.class);
					System.out.println("id\t\t" + newPerson.getId());
					System.out.println("name\t\t" + newPerson.getName());
					System.out.println("sex\t\t" + newPerson.getSex());
					System.out.println("age\t\t" + newPerson.getAge());
					System.out.println("isStudent\t\t"
							+ newPerson.getIsStudent());
				}
			} else {
				log.error("没有查询到任何内容!");
				return;
			}

			// 查询总数量
			long count = client.prepareCount(index).setTypes(type).setQuery(qb)
					.execute().actionGet().count();

			log.info("符合条件的总数量为:" + count);

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (null != client) {
				client.close();
			}
			if (null != node) {
				node.close();
			}
		}
	}
}

请注意:必须在 idsQuery 后为其设定 id ,设定 id 的方法有以下两种:

    /**
     * Adds ids to the filter.
     */
    public IdsQueryBuilder addIds(String... ids) {
        values.addAll(Arrays.asList(ids));
        return this;
    }

    /**
     * Adds ids to the filter.
     */
    public IdsQueryBuilder ids(String... ids) {
        return addIds(ids);
    }

 

 

七、MultiSearch

MultiSearch 是 Elasticsearch 提供针对多个查询请求进行一次查询的接口,该接口虽然能解决同时进行多个不同的查询,但存在一下问题:

  1. 无法对最终结果进行分页,除非人工分页;
  2. 有可能多个SearchRequest 查询出来的结果中,存在重复结果,但MultiSearch不负责去重。

org.elasticsearch.index.query.QueryBuilder 提供了一些同时执行多种不同 Query 的接口,可以自行研究;

示例图下:

package com.gsoft.gsearch.util;

import java.util.UUID;

import junit.framework.Assert;

import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.MultiSearchResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.junit.Test;

import com.gsoft.gsearch.BaseTest;
import com.gsoft.gsearch.entity.Person;

public class MultiSearchTest extends BaseTest {
	@Test
	public void multiSearchQuery() {
		try {

			// 创建索引
			BulkRequestBuilder builder = client.prepareBulk();

			for (int i = 0; i < 2; i++) {
				Person p = new Person();
				p.setId(UUID.randomUUID().toString());
				p.setAge(20);
				p.setIsStudent(false);
				p.setSex("男");
				p.setName("张三的车");

				String source = ElasticSearchUtil.BeanToJson(p);

				IndexRequest request = client.prepareIndex().setIndex(index)
						.setType(type).setId(p.getId()).setSource(source)
						.request();

				builder.add(request);
			}
			for (int i = 0; i < 2; i++) {
				Person p = new Person();
				p.setId(UUID.randomUUID().toString());
				p.setAge(20);
				p.setIsStudent(false);
				p.setSex("男");
				p.setName("李四的货");

				String source = ElasticSearchUtil.BeanToJson(p);

				IndexRequest request = client.prepareIndex().setIndex(index)
						.setType(type).setId(p.getId()).setSource(source)
						.request();

				builder.add(request);
			}

			BulkResponse bResponse = builder.execute().actionGet();
			if (bResponse.hasFailures()) {
				Assert.fail("创建索引出错!");
			}

			// 检索
			QueryBuilder qb1 = QueryBuilders.matchQuery("name", "张三");
			QueryBuilder qb2 = QueryBuilders.matchQuery("name", "李四");
			QueryBuilder qb3 = QueryBuilders.matchQuery("name", "车");
			QueryBuilder qb4 = QueryBuilders.matchQuery("name", "货");

			SearchRequestBuilder searchRB1 = client.prepareSearch(index)
					.setTypes(type).setQuery(qb1).setFrom(0).setSize(8);
			SearchRequestBuilder searchRB2 = client.prepareSearch(index)
					.setTypes(type).setQuery(qb2).setFrom(0).setSize(9);
			SearchRequestBuilder searchRB3 = client.prepareSearch(index)
					.setTypes(type).setQuery(qb3).setFrom(0).setSize(11);
			SearchRequestBuilder searchRB4 = client.prepareSearch(index)
					.setTypes(type).setQuery(qb4).setFrom(0).setSize(12);

			MultiSearchResponse response = client.prepareMultiSearch()
					.add(searchRB1)
					.add(searchRB2)
					.add(searchRB3)
					.add(searchRB4)
					.execute().actionGet();
			
			for (MultiSearchResponse.Item item : response.responses()) {
				SearchResponse searchResponse = item.response();
				SearchHits hits = searchResponse.getHits();
				if (null == hits || hits.totalHits() == 0) {
					log.error("使用matchPhraseQuery(\"name\", \"wa\")没有查询到任何结果!");
				} else {
					for (SearchHit hit : hits) {
						String json = hit.getSourceAsString();

						Person newPerson = mapper.readValue(json, Person.class);
						System.out.println("id\t\t" + newPerson.getId());
						System.out.println("name\t\t" + newPerson.getName());
						System.out.println("sex\t\t" + newPerson.getSex());
						System.out.println("age\t\t" + newPerson.getAge());
						System.out.println("isStudent\t\t"
								+ newPerson.getIsStudent());
					}
				}
				System.out.println("============================================");
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (null != client) {
				client.close();
			}
			if (null != node) {
				node.close();
			}
		}
	}
}

 

转载于:https://my.oschina.net/exit/blog/806982

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值