1、下载解压版"elasticsearch-7.2.0-windows-x86_64.zip",解压至"D:serverelasticsearch-7.2.0"目录;
2、下载“elasticsearch-analysis-ik-7.2.0.zip”,解压至“D:serverelasticsearch-7.2.0pluginselasticsearch-analysis-ik-7.2.0”;
3、配置“D:serverelasticsearch-7.2.0configelasticsearch.yml”文件:
# ======================== Elasticsearch Configuration ========================= # # NOTE: Elasticsearch comes with reasonable defaults for most settings. # Before you set out to tweak and tune the configuration, make sure you # understand what are you trying to accomplish and the consequences. # # The primary way of configuring a node is via this file. This template lists # the most important settings you may want to configure for a production cluster. # # Please consult the documentation for further information on configuration options: # https://www.elastic.co/guide/en/elasticsearch/reference/index.html # # ---------------------------------- Cluster ----------------------------------- # # Use a descriptive name for your cluster: # #cluster.name: my-application # # ------------------------------------ Node ------------------------------------ # # Use a descriptive name for the node: # #node.name: node-1 # # Add custom attributes to the node: # #node.attr.rack: r1 # # ----------------------------------- Paths ------------------------------------ # # Path to directory where to store the data (separate multiple locations by comma): # #path.data: /path/to/data # # Path to log files: # #path.logs: /path/to/logs # # ----------------------------------- Memory ----------------------------------- # # Lock the memory on startup: # bootstrap.memory_lock: true # # Make sure that the heap size is set to about half the memory available # on the system and that the owner of the process is allowed to use this # limit. # # Elasticsearch performs poorly when the system is swapping the memory. # # ---------------------------------- Network ----------------------------------- # # Set the bind address to a specific IP (IPv4 or IPv6): # network.host: 0.0.0.0 # # Set a custom port for HTTP: # http.port: 9200 # # For more information, consult the network module documentation. # # --------------------------------- Discovery ---------------------------------- # # Pass an initial list of hosts to perform discovery when this node is started: # The default list of hosts is ["127.0.0.1", "[::1]"] # discovery.seed_hosts: ["host1"] # # Bootstrap the cluster using an initial set of master-eligible nodes: # cluster.initial_master_nodes: ["node-1"] # # For more information, consult the discovery and cluster formation module documentation. # # ---------------------------------- Gateway ----------------------------------- # # Block initial recovery after a full cluster restart until N nodes are started: # #gateway.recover_after_nodes: 3 # # For more information, consult the gateway module documentation. # # ---------------------------------- Various ----------------------------------- # # Require explicit names when deleting indices: # #action.destructive_requires_name: true xpack.security.enabled: true xpack.security.transport.ssl.enabled: true
4、启动服务“D:serverelasticsearch-7.2.0inelasticsearch.bat”
5、下载解压curl-7.65.1-win64-mingw.zip至“D:curl-7.65.1-win64-mingw”,配置系统环境path增加路径“D:curl-7.65.1-win64-mingwin”;
6、运行dos命令, 执行“curl -help”验证是否配置成功;
7、在DOS窗口中,设置用户密码:
D:serverelasticsearch-7.2.0in>elasticsearch-setup-passwords auto
Changed password for user apm_system
PASSWORD apm_system = wXP7CnMmpulr70PrhOy9
Changed password for user kibana
PASSWORD kibana = 16P4FhGKQjRxTkI3c8KR
Changed password for user logstash_system
PASSWORD logstash_system = 1lyczLndTf2xACdJEt7U
Changed password for user beats_system
PASSWORD beats_system = jZRMVw05cQD8xxuCEleY
Changed password for user remote_monitoring_user
PASSWORD remote_monitoring_user = MR44yUAc046FihQDhO43
Changed password for user elastic
PASSWORD elastic = N0AE4qdTZp0l6zJzGNZ1
记住以上自动生成的密码;
8、在DOS窗口中,运行以下命令,创建索引并设置分词器,过滤器:
curl -u elastic:9lHDbltrSSIPmcjexseY -XPUT "http://192.168.1.230:9200/xuetz" -H "Content-Type:application/json" -d "{"settings":{"analysis":{"analyzer":{"myAnalyzer":{"tokenizer":"ik_max_word","char_filter":["html_strip"]}}}}}"
9、在DOS窗口中,运行以下命令,设置各个field属性对应的解析器:
curl -u elastic:9lHDbltrSSIPmcjexseY -XPUT "http://192.168.1.230:9200/xuetz/_mapping" -H "Content-Type:application/json" -d "{"properties":{"opName":{"type":"text","analyzer":"myAnalyzer","search_analyzer":"ik_smart"},"brief":{"type":"text","analyzer":"myAnalyzer","search_analyzer":"ik_smart"},"editor":{"type":"text","analyzer":"myAnalyzer","search_analyzer":"ik_smart"},"keywords":{"type":"text","analyzer":"myAnalyzer","search_analyzer":"ik_smart"}}}"
如一次性返回buckets数量大于10000,需设置search.max_buckets参数:
curl -u elastic:9lHDbltrSSIPmcjexseY -XPUT "http://192.168.1.230:9200/_cluster/settings" -H "Content-Type:application/json" -d "{"persistent":{"search.max_buckets":50000}}"
10、JAVA采用Java High Level REST Client 调用
10.1 ESBean.java
package com.xrh.extend.elasticsearch; public class ESBean implements java.io.Serializable { /** * */ private static final long serialVersionUID = -8973010685088776452L; private String id; //ID private String opName; //标题 private String opNameHL; //标题-高亮 private String brief; //简介 private String briefHL; //简介-高亮 private String keywords; //关键字 private String keyWordsHL;//关键字-高亮 private String editor; //内容 private String editorHL; //内容-高亮 private String picUrl; //封面图 private String opSite; //站点 private String parentId; //所属栏目ID或父级ID private String publishDate; //发布时间 private String tableName; //表名 private float score; //文档评分 public String getId() { return id; } public void setId(String id) { this.id = id; } public String getOpName() { return opName; } public void setOpName(String opName) { this.opName = opName; } public String getBrief() { return brief; } public void setBrief(String brief) { this.brief = brief; } public String getKeywords() { return keywords; } public void setKeywords(String keywords) { this.keywords = keywords; } public String getEditor() { return editor; } public void setEditor(String editor) { this.editor = editor; } public String getOpSite() { return opSite; } public void setOpSite(String opSite) { this.opSite = opSite; } public String getParentId() { return parentId; } public void setParentId(String parentId) { this.parentId = parentId; } public String getPublishDate() { return publishDate; } public void setPublishDate(String publishDate) { this.publishDate = publishDate; } public String getTableName() { return tableName; } public void setTableName(String tableName) { this.tableName = tableName; } public String getOpNameHL() { if (opNameHL == null){ return opName; } return opNameHL; } public void setOpNameHL(String opNameHL) { this.opNameHL = opNameHL; } public String getBriefHL() { if (briefHL == null){ return brief; } return briefHL; } public void setBriefHL(String briefHL) { this.briefHL = briefHL; } public String getKeyWordsHL() { if (keyWordsHL == null){ return keywords; } return keyWordsHL; } public void setKeyWordsHL(String keyWordsHL) { this.keyWordsHL = keyWordsHL; } public String getEditorHL() { if (editorHL == null){ return editor; } return editorHL; } public void setEditorHL(String editorHL) { this.editorHL = editorHL; } public float getScore() { return score; } public void setScore(float score) { this.score = score; } public String getPicUrl() { return picUrl; } public void setPicUrl(String picUrl) { this.picUrl = picUrl; } }
10.2 ESResult.java
package com.xrh.extend.elasticsearch; import java.util.List; public class ESResult { private List<ESBean> datas; private long totalHits; public List<ESBean> getDatas() { return datas; } public void setDatas(List<ESBean> datas) { this.datas = datas; } public long getTotalHits() { return totalHits; } public void setTotalHits(long totalHits) { this.totalHits =totalHits; } }
10.3 ESTool.java
package com.xrh.extend.elasticsearch; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.logging.Logger; import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.config.RequestConfig.Builder; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; import org.elasticsearch.action.DocWriteResponse; import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.delete.DeleteResponse; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.action.update.UpdateResponse; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClientBuilder; import org.elasticsearch.client.RestClientBuilder.HttpClientConfigCallback; import org.elasticsearch.client.RestClientBuilder.RequestConfigCallback; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.text.Text; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightField; import com.xrh.base.config.DAO_Config; import com.xrh.core.util.JsonUtil; import com.xrh.core.util.ObjectUtil; public class ESTool { private static Logger logger = Logger.getLogger(ESTool.class.getName()); private RestHighLevelClient restClient = null; public ESTool(){ String hosts = DAO_Config.getConfigValue("es-hosts"); // 集群地址 String port = DAO_Config.getConfigValue("es-port"); // 使用的端口号 String schema = DAO_Config.getConfigValue("es-schema"); // 使用的协议 if (ObjectUtil.isNull(hosts)){ logger.info("ES集群地址不能为空!无法完成初始化."); return ; } if (ObjectUtil.isNull(port)){ logger.info("ES端口后不能为空!无法完成初始化."); return ; } if (ObjectUtil.isNull(schema)){ logger.info("ES协议不能为空!无法完成初始化."); return ; } ArrayList<HttpHost> hostList = new ArrayList<>(); String[] hostStrs = hosts.split(","); for (String host : hostStrs) { hostList.add(new HttpHost(host, Integer.parseInt(port), schema)); } RestClientBuilder builder = RestClient.builder(hostList.toArray(new HttpHost[0])) .setFailureListener(new RestClient.FailureListener() { // 连接失败策略 // }).setRequestConfigCallback(new RequestConfigCallback() { @Override public Builder customizeRequestConfig(Builder requestConfigBuilder) { String connectTimeOut = DAO_Config.getConfigValue("es-connectTimeOut"); if (!ObjectUtil.isNull(connectTimeOut)){ requestConfigBuilder.setConnectTimeout(Integer.parseInt(connectTimeOut)); } String socketTimeout = DAO_Config.getConfigValue("es-socketTimeout"); if (!ObjectUtil.isNull(socketTimeout)){ requestConfigBuilder.setSocketTimeout(Integer.parseInt(socketTimeout)); } String connectionRequestTimeout = DAO_Config.getConfigValue("es-connectionRequestTimeout"); if (!ObjectUtil.isNull(connectionRequestTimeout)){ requestConfigBuilder.setConnectionRequestTimeout(Integer.parseInt(connectionRequestTimeout)); } return requestConfigBuilder; } }) .setHttpClientConfigCallback(new HttpClientConfigCallback() { // 认证 @Override public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) { String maxConnTotal = DAO_Config.getConfigValue("es-maxConnTotal"); if (!ObjectUtil.isNull(maxConnTotal)){ httpClientBuilder.setMaxConnTotal(Integer.parseInt(maxConnTotal)); } String maxConnPerRoute = DAO_Config.getConfigValue("es-maxConnPerRoute"); if (!ObjectUtil.isNull(maxConnPerRoute)){ httpClientBuilder.setMaxConnTotal(Integer.parseInt(maxConnPerRoute)); } String userName = DAO_Config.getConfigValue("es-userName"); String password = DAO_Config.getConfigValue("es-password"); if (ObjectUtil.isNull(userName) || ObjectUtil.isNull(password)){ return httpClientBuilder; }else{ CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(userName, password)); return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); } } }); restClient = new RestHighLevelClient(builder); } /** * 生成索引文档(重复则自动更新) * @param bean * @return */ public boolean doSave(ESBean bean){ if (restClient == null){ logger.info("系统未配置搜索服务参数,无法完成索引保存操作!"); return false; } if(bean == null){ logger.info("bean 对象为空,无法创建索引!"); return false; } if (ObjectUtil.isNull(bean.getOpSite())){ logger.info("对象opSite为空,无法创建索引!"); return false; } if (ObjectUtil.isNull(bean.getTableName())){ logger.info("对象tableName为空,无法生成文档唯一ID!"); return false; } if (ObjectUtil.isNull(bean.getId())){ logger.info("对象id为空,无法生成文档唯一ID!"); return false; } XContentBuilder builder = getXContentBuilder(bean); UpdateRequest request = new UpdateRequest(bean.getOpSite(), generateId(bean.getTableName(), bean.getId())) .doc(builder) .upsert(builder);//upsert--id不存在时就插入 try { UpdateResponse response = restClient.update(request, RequestOptions.DEFAULT); response.forcedRefresh(); if (response.status().equals(RestStatus.OK) || response.status().equals(RestStatus.CREATED)){ logger.info("索引文档【id="+bean.getId()+" opName="+bean.getOpName()+"】保存成功!"); return true; }else{ logger.info("保存失败,状态="+response.status()+" "+response.toString()); return false; } } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); return false; } } /** * 删除索引文档 * @param site 站点ID * @param tableName 表名 * @param id 主键 * @return */ public boolean doDelete(String site, String tableName, String id){ if (restClient == null){ logger.info("系统未配置搜索服务参数,无法完成索引删除操作!"); return false; } if (ObjectUtil.isNull(site)){ logger.info("site为空,定位索引!"); return false; } DeleteRequest request = new DeleteRequest() .index(site) .id(generateId(tableName, id)); try { DeleteResponse deleteResponse = restClient.delete( request, RequestOptions.DEFAULT); if (deleteResponse.getResult() == DocWriteResponse.Result.NOT_FOUND) { logger.info("未找到要删除的文档【"+generateId(tableName, id)+"】"); return true; } if (deleteResponse.status().equals(RestStatus.OK)){ logger.info("文档【"+generateId(tableName, id)+"】删除成功!"); return true; }else{ logger.info("删除状态="+deleteResponse.status() + " "+deleteResponse.toString()); return false; } } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); return false; } } /** * 搜索文档 * @param site 站点ID * @param sourceBuilder searchSourceBuilder * @param from 起始位置 * @param size 获取条数 * @param highlightFields 高亮属性 * @return */ public ESResult doSearch(String site, SearchSourceBuilder sourceBuilder, int from, int size, String[] highlightFields){ if (restClient == null){ logger.info("系统未配置搜索服务参数,无法完成检索操作!"); return null; } if (ObjectUtil.isNull(site)){ logger.info("site为空,定位索引!"); return null; } SearchRequest searchRequest = new SearchRequest(); searchRequest.indices(site); sourceBuilder.from(from); //设置from选项,确定要开始搜索的结果索引。 默认为0。 sourceBuilder.size(size); //设置大小选项,确定要返回的搜索匹配数。 默认为10。 String timeout = DAO_Config.getConfigValue("es-timeout"); //搜索超时时间 if (!ObjectUtil.isNull(timeout)){ sourceBuilder.timeout(new TimeValue(Integer.parseInt(timeout))); } if (highlightFields != null){ String preTags = DAO_Config.getConfigValue("es-preTags"); //高亮前缀 String postTags = DAO_Config.getConfigValue("es-postTags"); //高亮后缀 HighlightBuilder highlightBuilder = new HighlightBuilder(); for (String highlightField : highlightFields){ HighlightBuilder.Field field = new HighlightBuilder.Field(highlightField); highlightBuilder.field(field); } if (!ObjectUtil.isNull(preTags) && !ObjectUtil.isNull(postTags)){ highlightBuilder.preTags(preTags); highlightBuilder.postTags(postTags); } sourceBuilder.highlighter(highlightBuilder); } searchRequest.source(sourceBuilder); try { SearchResponse response = restClient.search(searchRequest, RequestOptions.DEFAULT); logger.info("文档搜索结果 status="+response.status()); ESResult esResult = new ESResult(); SearchHits searchHits = response.getHits(); esResult.setTotalHits(searchHits.getTotalHits().value); List<ESBean> datas = new ArrayList(); Iterator<SearchHit> iterator = searchHits.iterator(); while (iterator.hasNext()){ SearchHit searchHit = iterator.next(); ESBean data = JsonUtil.json2Obj(searchHit.getSourceAsString(), ESBean.class); data.setScore(searchHit.getScore()); if (highlightFields != null){ Map<String, HighlightField> hlFieldsMap = searchHit.getHighlightFields(); for (String highlightField : highlightFields){ if (hlFieldsMap.containsKey(highlightField)){ HighlightField highlight = hlFieldsMap.get(highlightField); Text[] fragments = highlight.fragments(); if (fragments.length > 0){ StringBuffer sb = new StringBuffer();; for (Text fragment : fragments){ sb.append(fragment.string()); } if (highlightField.toLowerCase().equals("opname")){ data.setOpNameHL(sb.toString()); } else if (highlightField.toLowerCase().equals("brief")){ data.setBriefHL(sb.toString()); } else if (highlightField.toLowerCase().equals("keywords")){ data.setKeyWordsHL(sb.toString()); } else if (highlightField.toLowerCase().equals("editor")){ data.setEditorHL(fiterHtmlTag(sb.toString())); } else { logger.info("highlightField【"+highlightField+"】不在ESBean属性范围!"); } } } } } datas.add(data); } esResult.setDatas(datas); return esResult; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } /** * 关闭restClient对象 */ public void close(){ try { if (restClient != null){ restClient.close(); restClient = null; } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private static String fiterHtmlTag(String html){ String filterTags = "(?!<(font|/font|em|/em).*?>)<.*?>"; //html不过滤的标签 if (!ObjectUtil.isNull(filterTags) && !ObjectUtil.isNull(html)){ return html.replaceAll(filterTags, ""); } return html; } /** * 生成索引文档对象 * @param bean * @return */ private XContentBuilder getXContentBuilder(ESBean bean){ XContentBuilder builder = null; try { builder = XContentFactory.jsonBuilder().startObject() .field("id", bean.getId()) .field("opName", bean.getOpName()) .field("brief", bean.getBrief()) .field("keywords", bean.getKeywords()) .field("editor", bean.getEditor()) .field("opSite", bean.getOpSite()) .field("parentId", bean.getParentId()) .field("picUrl", bean.getPicUrl()) .field("publishDate", bean.getPublishDate()) .field("tableName", bean.getTableName()) .endObject(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return builder; } /** * 生成文档ID * @param tableName 表名 * @param id 主键 * @return */ private String generateId(String tableName, String id){ return tableName + "_" + id; } public static void main(String[] args){ ESTool esTool = new ESTool(); SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); sourceBuilder.query(QueryBuilders.boolQuery() .must(QueryBuilders.multiMatchQuery("住房公积金管理中心服务大厅", "opName", "editor", "brief", "keywords")) // 自动分词匹配 // .must(QueryBuilders.termsQuery("parentId","21","46")) // 全匹配(文本不会进行分词),可一次匹配多个值 // .must(QueryBuilders.rangeQuery("publishDate") // .from("2019-01-01 00:00:00").to("2019-01-31 23:59:59")) //区间搜索 ); ESResult result = esTool.doSearch("xuetz", sourceBuilder, 0, 2, new String[]{"opName", "brief"}); esTool.close(); } }