我们采用2.1版本,2.1版本和1.x版本在api上面有许多不同之处,从1.x版本升级上来的伙伴需要注意,api用法上面都能找到对应的使用。具体的api请参照
https://www.elastic.co/guide/en/elasticsearch/client/java-api/2.1/index.html
<dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>2.1.2</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>20.0</version> </dependency>
建立服务器连接
这一步类似mysql数据库要获取一个DataSource
核心代码
public interface ElasticSearchSource {
public Client getClient();
}
import com.jd.poplog.dao.elasticsearch.ElasticSearchSource;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class ElasticSearchClientFactory implements ElasticSearchSource{
private String clusterName;
private Client client;
static public TransportClient tclient = null;
public Client getClient() {
return client;
}
/**
* 创建es client
* clusterName:集群名字
* nodeIp:集群中节点的ip地址
* nodePort:节点的端口
*
* @return
*/
public void init() throws ElasticsearchException {
synchronized (this){
Settings settings = Settings.settingsBuilder()
.put("cluster.name", clusterName).build();
//创建集群client并添加集群节点地址
tclient = TransportClient.builder().settings(settings).build();
try {
tclient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("192.168.200.189"),9303))//以下是新增加节点
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("192.168.200.190"),9303));
client = tclient;
} catch (UnknownHostException e) {
e.printStackTrace();
} finally {
}
}
}
public void close() {
if (null != client) {
client.close();
}
}
public void setClusterName(String clusterName) {
this.clusterName = clusterName;
}
}
索引数据
有三种方法,使用json字符串,使用map,使用业务bean,参考:
我们介绍使用bean的方法,也是平时开发中最常用的方法,这里包含索引时候的路由字段,当然查询的时候也要根据这个路由字段
public <T> boolean indexWithBean(T t,String routingId) throws ESException { try{ //用javabean构建json对象 ObjectMapper mapper = new ObjectMapper(); byte[] json = mapper.writeValueAsBytes(t); //指定索引名称,type名称和documentId(documentId可选,不设置则系统自动生成)创建document IndexResponse response = elasticSearchSource.getClient().prepareIndex(indexName, indexType) .setSource(json) .setRouting(routingId) .execute() .actionGet(); boolean created = response.isCreated(); return created; }catch (Exception e){ _logger.error("indexWithBean is err.",e); throw new ESException("insert into es exception",e); } }
查询数据
查询稍微复杂一些,涉及分页,高亮,分词等动作,我们一一来描述
分页相关类:
import java.util.List; public interface PaginatedList<T> extends List<T> { boolean isMiddlePage(); boolean isLastPage(); boolean isNextPageAvailable(); boolean isPreviousPageAvailable(); int getPageSize(); void setPageSize(int var1); int getIndex(); void setIndex(int var1); int getTotalItem(); void setTotalItem(int var1); int getTotalPage(); int getStartRow(); int getEndRow(); int getNextPage(); int getPreviousPage(); boolean isFirstPage(); } import java.util.ArrayList; public class Page<T> extends ArrayList<T> implements PaginatedList<T> { /** * 默认每页的记录数量 */ public static final int PAGESIZE_DEFAULT = 20; /** * 每页大小 */ private int pageSize; /** * 当前页。第一页是1 */ private int index; /** * 总记录数 */ private int totalItem; /** * 总页数 */ private int totalPage; /** * 分页后的记录开始的地方 * 第一条记录是1 */ private int startRow; /** * 分页后的记录结束的地方 */ private int endRow; /** * 默认构造方法 */ public Page() { repaginate(); } /** * 带当前页和页大小的构造方法 * * @param index 当前页 * @param pageSize 页大小 */ public Page(int index, int pageSize) { this.index = index; this.pageSize = pageSize; repaginate(); } /** * 表示是不是第一页 * * @return true 是; false 不是 */ public boolean isFirstPage() { return index <= 1; } public boolean isMiddlePage() { return !(isFirstPage() || isLastPage()); } public boolean isLastPage() { return index >= totalPage; } public boolean isNextPageAvailable() { return !isLastPage(); } public boolean isPreviousPageAvailable() { return !isFirstPage(); } /** * 下一页号 * * @return 取得下一页号 */ public int getNextPage() { if (isLastPage()) { return totalItem; } else { return index + 1; } } public int getPreviousPage() { if (isFirstPage()) { return 1; } else { return index - 1; } } /** * Method getPageSize returns the pageSize of this PaginatedArrayList object. * <p/> * 每页大小 * * @return the pageSize (type int) of this PaginatedArrayList object. */ public int getPageSize() { return pageSize; } /** * Method setPageSize sets the pageSize of this PaginatedArrayList object. * <p/> * 每页大小 * * @param pageSize the pageSize of this PaginatedArrayList object. */ public void setPageSize(int pageSize) { this.pageSize = pageSize; repaginate(); } /** * Method getIndex returns the index of this PaginatedArrayList object. * <p/> * 当前页。第一页是1 * * @return the index (type int) of this PaginatedArrayList object. */ public int getIndex() { return index; } /** * Method setIndex sets the index of this PaginatedArrayList object. * <p/> * 当前页。第一页是1 * * @param index the index of this PaginatedArrayList object. */ public void setIndex(int index) { this.index = index; repaginate(); } /** * Method getTotalItem returns the totalItem of this PaginatedArrayList object. * <p/> * 总记录数 * * @return the totalItem (type int) of this PaginatedArrayList object. */ public int getTotalItem() { return totalItem; } /** * Method setTotalItem sets the totalItem of this PaginatedArrayList object. * <p/> * 总记录数 * * @param totalItem the totalItem of this PaginatedArrayList object. */ public void setTotalItem(int totalItem) { this.totalItem = totalItem; repaginate(); } /** * Method getTotalPage returns the totalPage of this PaginatedArrayList object. * <p/> * 总页数 * * @return the totalPage (type int) of this PaginatedArrayList object. */ public int getTotalPage() { return totalPage; } /** * Method getStartRow returns the startRow of this PaginatedArrayList object. * <p/> * 分页后的记录开始的地方 * * @return the startRow (type int) of this PaginatedArrayList object. */ public int getStartRow() { return startRow; } /** * Method getEndRow returns the endRow of this PaginatedArrayList object. * <p/> * 分页后的记录结束的地方 * * @return the endRow (type int) of this PaginatedArrayList object. */ public int getEndRow() { return endRow; } /** * Method repaginate ... */ private void repaginate() { if (pageSize < 1) { //防止程序偷懒,list和分页的混合使用 pageSize = PAGESIZE_DEFAULT; } if (index < 1) { index = 1;//恢复到第一页 } if (totalItem > 0) { totalPage = totalItem / pageSize + (totalItem % pageSize > 0 ? 1 : 0); if (index > totalPage) { index = totalPage; //最大页 } endRow = index * pageSize; //起始startRow应为0 startRow = endRow - pageSize; if (endRow > totalItem) { endRow = totalItem; } } } }
elasticsearch相关
public <T> List<T> getByQueryBean(OpLogQuery opLogQuery,PaginatedList page,String sortField,GetMapping<T> get) { List<T> logs = new ArrayList<T>(); try{ int startRow= (page.getIndex()-1)*page.getPageSize(); BoolQueryBuilder builder = buildBoolQuery(opLogQuery); QueryBuilder range = QueryBuilders.rangeQuery("opTime").gte(startTime).lt(endTime)); builder.must(range); SearchResponse sResponse = elasticSearchSource.getClient().prepareSearch(indexName1,indexName2,...)//这里可以跨多个索引查询,比如每天一个索引的时候,es的这种api非常方便 .setTypes(esType) .setSearchType(SearchType.QUERY_THEN_FETCH) .setQuery(builder) //设置排序field .addSort(sortField, SortOrder.DESC) //设置高亮field .addHighlightedField("opContent") //设置分页 .setFrom(startRow).setSize(page.getPageSize()) .execute() .actionGet(); SearchHits hits = sResponse.getHits(); int count = (int) hits.getTotalHits(); page.setTotalItem(count); SearchHit[] hitArray = hits.getHits(); for (int i = 0; i < hitArray.length; i++) { SearchHit hit = hitArray[i]; logs.add(get.mapping(hit)); } }catch (Exception e){ throw new ESException("query es EXCPTION",e); } return logs; } //通过这个方法可以把查询条件组装到BoolQueryBuilder 中 private BoolQueryBuilder buildBoolQuery(OpLogQuery opLogQuery) { Map<String,String> map = new HashMap<String, String>(); map.put("bizType",opLogQuery.getBusinessType()); map.put("opObject",opLogQuery.getOperateObj()); BoolQueryBuilder boolQuery = new BoolQueryBuilder(); for (Map.Entry<String, String> entry : map.entrySet()){ if (StringUtils.isNotBlank(entry.getValue())&&!DEFAULT_VALUE.equals(entry.getValue())){ // boolQuery.must(QueryBuilders.matchQuery(entry.getKey(), entry.getValue())); boolQuery.must(QueryBuilders.prefixQuery(entry.getKey(), entry.getValue())); } } return boolQuery; }
关于GetMappingimport org.elasticsearch.search.SearchHit; public interface GetMapping<T> { T mapping(SearchHit hit); }
调用elasticSearchDao.getByQueryBean(opLogQuery, page, "opTime", new GetMapping<OpLog>() { @Override public OpLog mapping(SearchHit hit) { OpLog opLog = new OpLog(); Map<String, Object> fields = hit.getSource(); opLog.setVenderId(fields.get("venderId").toString()); opLog.setOpUser(fields.get("opUser").toString()); opLog.setOpTime(fields.get("opTime").toString()); //设置高亮 Map<String, HighlightField> result = hit.getHighlightFields(); if(result.size()>0){ HighlightField opContentField = result.get("opContent"); Text[] opContentTexts = opContentField.getFragments(); for(Text text : opContentTexts){ opLog.setOpValue(text.string()); } } return opLog; } });
到此,Elasticsearch的基本插入和查询就介绍完毕。
参考资料:https://www.elastic.co/guide/en/elasticsearch/client/java-api/2.1/java-docs-index.html