elasticsearch-7.2.0 在windows环境的部署应用

1、下载解压版"elasticsearch-7.2.0-windows-x86_64.zip",解压至"D:\server\elasticsearch-7.2.0"目录;

2、下载“elasticsearch-analysis-ik-7.2.0.zip”,解压至“D:\server\elasticsearch-7.2.0\plugins\elasticsearch-analysis-ik-7.2.0”;

3、配置“D:\server\elasticsearch-7.2.0\config\elasticsearch.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:\server\elasticsearch-7.2.0\bin\elasticsearch.bat”

5、下载解压curl-7.65.1-win64-mingw.zip至“D:\curl-7.65.1-win64-mingw”,配置系统环境path增加路径“D:\curl-7.65.1-win64-mingw\bin”;

6、运行dos命令, 执行“curl -help”验证是否配置成功;

7、在DOS窗口中,设置用户密码:

D:\server\elasticsearch-7.2.0\bin>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();
 
    }
}

 

posted @ 2019-07-11 10:46  李小加  阅读(2556)  评论(0编辑  收藏  举报