前言
前些日子,elastic公司成功上市了。旗下有一款优秀的开源搜索引擎ElasticSearch。
ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。
好了,扯远了,回归正题。今天我们使用Java对它的一些API进行封装,以使其API更具备灵活性。
完成对其简单的使用是比较简单的,我们今天把我们的一些调用代码封装,以便可以在各个项目中自由使用。这才是我们的根本目的。
今天,我们来构建一个工具包类。
环境准备
安装ElasticSearch,主要就是为了测试我们的代码,对于有现成环境的,如开发环境,测试环境上的ElasticSearch,这一步可以忽略。
首先请安装ElasticSearch,这里就不介绍了,我这里是安装的ElasticSearch最新版,6.4.0版本。https://www.elastic.co/downloads/elasticsearch 。安装成功后可以将其添加到环境变量中,然后启动。启动成功浏览器访问http://localhost:9200/ 会看到json信息。
安装Kibana,Kibana是ElasticSearch的可视化工具,可以方便的查看ElasticSearch及其运行状态。https://www.elastic.co/products/kibana 。我安装的也是最新版本,6.4.0. 安装成功后加入环境变量,然后启动,访问http://localhost:5601/ 可以看到Kibana界面。
JDK版本为1.8
以上都为准备工作。
架构构建
org.elasticsearch.client.transport jar包已经有相关关于ES API的操作。
我们把它封装为专用jar包,建议使用Maven构建。如下:
Maven项目
首先,我们先建一个名叫 framework-es的Maven项目。如下。
建好各个package。
exception里面定义我们的异常。
factory里面用来生成esclient。
util里面放一些工具类。
vo里面可以放查询对象等。
property为配置文件。
test里面存放测试类。
各个package的名字可以自己定义,描述清目的即可。如下图。
添加依赖
添加依赖,我的pom.xml依赖如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <dependencies> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>transport</artifactId> <version>6.4.0</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.31</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> </dependencies>
|
思路
我的思路是构建一个单例的ESClient,用于与ES建立连接,以后增删改查等逻辑均使用此Client,保证资源的高效利用。这个也应当支持ES集群,有多个ES服务端也应当支持。而且地址应为可配置的。
话不多说,上代码,主要代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| public class ElasticSearchClientFactory { private final static Logger logger = LoggerFactory.getLogger(ElasticSearchClientFactory.class); private volatile TransportClient esClient; private ElasticSearchConfiguration esConfig; private Pattern addRessPattern = Pattern.compile("^.+[:]\\d{1,5}\\s*(;.+[:]\\d{1,5}\\s*)*[;]?\\s*$"); public ElasticSearchClientFactory(final ElasticSearchConfiguration elasticSearchConfiguration){ this.esConfig=elasticSearchConfiguration; }
public Client getEsClient(){ if(esClient==null){ synchronized (ElasticSearchClientFactory.class){ if(esClient==null){ logger.info("ElasticSearchClientFactory init start..."); try{ if(StringUtils.isNotBlank(esConfig.getLocalPropertiesPath())){ fillData(); } logger.info("ESConfig is:{}",esConfig.toString()); List<HostAndPort> hostAndPortList = this.parseHostAndPortList(esConfig.getAddress()); TransportAddress [] transportAddress=new TransportAddress[hostAndPortList.size()]; for (int i = 0; i < hostAndPortList.size(); i++) { transportAddress[i] = new TransportAddress(InetAddress.getByName(hostAndPortList.get(i).getIp()),hostAndPortList.get(i).getPort()); } String nodeName=esConfig.getNodeName()+ UUID.randomUUID(); String clusterName=esConfig.getClusterName(); Settings.Builder settingsBuilder = Settings.builder(); settingsBuilder.put("node.name", nodeName); if(StringUtils.isNotBlank(clusterName)){ settingsBuilder.put("cluster.name", clusterName); } settingsBuilder.put("client.transport.sniff", true); Settings settings = settingsBuilder.build(); TransportClient client = new PreBuiltTransportClient(settings); esClient = client.addTransportAddresses(transportAddress); logger.info("EalsticSearchClientFactory init is finished"); }catch(Exception e){ logger.error("EalsticSearchClientFactory create failed",e); throw new ElasticSearchException("EalsticSearchClientFactory create faile",e); } } } } return esClient; } }
|
以上代码用于生成一个单例的ESClient类。
1 2 3
| public class ElasticSearchConstants { public final static String DEFAULT_PROPERTIES_PATH="property/es-config.properties"; }
|
同时默认配置文件为property/es-config.properties
可手动进行配置,且支持多个地址,地址写法为 127.0.0.1:9200;127.0.0.2:9300
这样,中间应使用;分割。
我们对外提供一个工具类,供使用者进行对数据的操作。如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| public class ElasticSearchUtil { private final static Logger logger = LoggerFactory.getLogger(ElasticSearchUtil.class); private static final SerializerFeature[] featuresWithNullValue={SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullBooleanAsFalse, SerializerFeature.WriteNullListAsEmpty, SerializerFeature.WriteNullNumberAsZero, SerializerFeature.WriteNullStringAsEmpty}; private ElasticSearchClientFactory elasticSearchClientFactory; public void setElasticSearchClientFactory(ElasticSearchClientFactory elasticSearchClientFactory) { this.elasticSearchClientFactory = elasticSearchClientFactory; }
public ElasticSearchUtil(ElasticSearchClientFactory elasticSearchClientFactory){ this.elasticSearchClientFactory=elasticSearchClientFactory; } public ElasticSearchUtil(String localPropertiesPath){ ElasticSearchConfiguration esConfig=new ElasticSearchConfiguration(); esConfig.setLocalPropertiesPath(localPropertiesPath); this.elasticSearchClientFactory=new ElasticSearchClientFactory(esConfig); } public ElasticSearchUtil() { ElasticSearchConfiguration esConfig = new ElasticSearchConfiguration(); esConfig.setLocalPropertiesPath(ElasticSearchConstants.DEFAULT_PROPERTIES_PATH); this.elasticSearchClientFactory = new ElasticSearchClientFactory(esConfig); } public ElasticSearchUtil(ElasticSearchConfiguration esConfig) { this.elasticSearchClientFactory = new ElasticSearchClientFactory(esConfig); } public Client getEsClient() { return elasticSearchClientFactory.getEsClient(); }
protected boolean createDocument(String index,String type,String id,boolean isOnlyCreate,String jsonString){ IndexResponse indexResponse; if(StringUtils.isBlank(id)){ indexResponse=elasticSearchClientFactory.getEsClient().prepareIndex(index,type).setCreate(isOnlyCreate).setSource(jsonString, XContentType.JSON).get(); }else{ indexResponse=elasticSearchClientFactory.getEsClient().prepareIndex(index,type,id).setCreate(isOnlyCreate).setSource(jsonString,XContentType.JSON).get(); }
if(logger.isDebugEnabled()){ String _index=indexResponse.getIndex(); String _type=indexResponse.getType(); String _id=indexResponse.getId(); long _version = indexResponse.getVersion(); boolean created = RestStatus.CREATED.equals(indexResponse.status()); logger.debug(String.format("createDocument index:%s,type:%s,id:%s,version:%s,created:%s", _index, _type, _id, _version, created)); }
return RestStatus.CREATED.equals(indexResponse.status()); } }
|
创建好客户端后,我们可以用它执行增删改查,我们在封装一个ESUtil类,用于执行该系列操作,暴露一些特定增删改查接口。如上代码。
注:其他代码略。
这样,完成代码后,工程项目如下图所示。
ElasticSearchException 为自定义异常类。
ElasticSearchClientFactory为主要方法,用来构建一个单例的ESClient
ElasticSearchConfiguration为ES配置类
ElasticSearchConstants为常量类,里面存放配置文件的路径
HostAndPort为地址和端口的一个辅助Bean
ElasticSearchUtil为主要方法,用于对外提供服务(CRUD)
DocumentVo为辅助Bean
es-config.properties为配置文件
当我们把项目打包成jar包时,配置文件可以不用打包,这样引入其他项目后,在其他项目里配置配置文件即可。
测试
若ES的安装路径D:\Program Files\elasticsearch-6.4.0\bin成功配置到环境变量后,在命令行输入elasticsearch便可启动服务。
若Kibana的安装路径D:\Program Files\kibana-6.4.0-windows-x86_64成功配置到环境变量后,在命令行输入kibana便可启动服务。
访问http://127.0.0.1:5601/ 看到可视化界面。
编写测试类。
1 2 3 4 5 6 7 8 9 10
| public class ESTest { private static ElasticSearchUtil esUtil=new ElasticSearchUtil(); private static String index="user_index"; private static String type="user_type"; public static void main(String[] args) { JSONObject js=new JSONObject(); js.put("1","2"); esUtil.insertDocument(index,type,"123",js); } }
|
查看Kibana界面可以看到我们的数据被添加进来了。
结论
关于ElasticSearch及Kibana的具体使用我们以后再讲。
我们平时开发中,也可以创建类似的工具包,提高代码使用率,实现软件的高内聚低耦合,同时也是提高自己。
部分未展示代码请见我的GitHub地址: https://github.com/javazwt/