使用java操作Elasticsearch创建自定义索引

      ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。

     我们最熟悉的百度搜索便是应用了Elasticsearch,es提供了高亮、聚合统计、分组查询等。它在分布式部署下提供了强大的索引能力,使其具有极强的实时性,大量应用于项目开发中各种实时的应用场景。它有以下优点:

1.分布式文件存储,而且把每个字段编入索引,使其查询高效速度快

2.扩展性强,便于横向扩展,可处理PB级数据

3.利用其分片和master选举,使其具有较强的容错机制

简单说下linux下部署es集群:

        一般只要修改config下的elasticsearch.yml配置文件即可

# https://www.elastic.co/guide/en/elasticsearch/reference/index.html
#
# ---------------------------------- Cluster -----------------------------------
#
# Use a descriptive name for your cluster:
#
#cluster.name: my-application
cluster.name: cluster1
# ------------------------------------ Node ------------------------------------
#
# Use a descriptive name for the node:
#
#node.name: node-1
node.name: node1
# 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.data: /data/es/data
# Path to log files:
#
#path.logs: /path/to/logs
path.logs: /data/es/logs
# ----------------------------------- Memory -----------------------------------
#
# Lock the memory on startup:
#
#bootstrap.memory_lock: true
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: 192.168.0.1
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 new node is started:
# The default list of hosts is ["127.0.0.1", "[::1]"]
#
#discovery.zen.ping.unicast.hosts: ["host1", "host2"]
discovery.zen.ping.unicast.hosts: [ "192.168.xx.xxx", "192.168.xx.xxx", "192.168.xx.xxx"]

cluster.name:  集群名称,每个es节点必须拥有相同的集群名称

node.name:节点名称

network.host:节点所在服务器的ip地址,如果要在浏览器直接访问该节点可改为0.0.0.0

http.port:服务端端口,默认9200

discovery.zen.ping.unicast.hosts:集群内所有节点,可用ip也可用节点名称

如果需要增加jvm的内存,可修改config下的jvm.options

接下来重点讲解java中如何连接elasticsearch集群和创建索引及type,且自定义它的结构,本文不会展示全部代码,因为代码量多,主要讲解一个封装思路,后面讲到springboot我会把代码发布到gitHub

创建一个ElasticsearchServiceImpl实现类

1.启动初始化es

 

@PostConstruct   //改注解为启动服务便初始化运行该方法
    private void init() {
        getHosts();     //加入所有节点
        if (connectWhenStartup) {    //此为是否要启动便连接es,可自行增加配置文件设置
            connect();
        }
        createBuiltInIndices();  //创建索引
    }

我们来看看创建索引这个方法

 private void createBuiltInIndices() {
        String indexName;
        BaseIndexModel model;   //实体类基类
        for (Class clazz : DataModelUtils.getBuiltInClazzes()) {  
            List<DataItem> dataItems = DataModelUtils.getModelDataItems(clazz);
            try {
                model = (BaseIndexModel) clazz.newInstance();  //通过反射实例化
                indexName = model.getIndexName();
                if (!indexExists(indexName)) {  //判断索引是否存在,不存在则创建索引
                    createIndexNType(indexName, dataItems);  //创建索引
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }
    }

大家看到这个地方可能有点迷糊,BaseIndexModel是啥,BaseIndexModel是我自定义的一个基类,所有要存入es的实体都继承这个基类,然后通过自行创建的配置文件properties:

people=cn.gzis.gxpt.core.biz.model.People
student=cn.gzis.gxpt.core.biz.enterprise.model.Student

 DataModelUtils.getBuiltInClazzes()方法便是我自己编写的一个处理properties的静态方法,然后通过反射给每一个实体实例化,且基类中有一个getIndexName()方法,用来获取properties中的key,用key作为该实体在es中的索引名。

DataModelUtils.getModelDataItems(clazz)方法是通过反射获取该类所有字段,

最后把字段和索引名传入createIndexNType()方法中,用于创建索引。

 

接下来我们来看看创建type这个方法

 public boolean createType(String indexName, Collection<DataItem> dataItems) {
        if (StringUtils.isBlank(indexName) || null == dataItems || dataItems.isEmpty()) {
            return false;
        }
        boolean flag;
        logger.debug("准备创建Type...");
        try {
            XContentBuilder xcb = XContentFactory.jsonBuilder().startObject().startObject(ELASTICSEARCH_TYPE).startObject("properties"); //创建json结构
            for (DataItem dataItem : dataItems) {   //遍历数据项,需要有一个数据项的实体
                xcb = xcb.startObject(dataItem.getEname())
                        .field("type", "text")
                        .field("store", "yes")
                        .field("fielddata", "true")
                        .startObject("fields")
                        .startObject("keyword")
                        .field("type", "keyword").field("ignore_above", 256)
                        .endObject();
                if (DataItemType.NUMBER.equals(dataItem.getType())) {  //根据类型创建mapping数据结构
                    xcb = xcb.startObject("number").field("type", "double").endObject();
                }
//                if (DataItemType.DATE.equals(dataItem.getType())) {
//                    xcb = xcb.startObject("date").field("type", "date").field("format", "yyyy-MM-dd").endObject();
//                }
                if (DataItemType.DATETIME.equals(dataItem.getType())) {
                    xcb = xcb.startObject("date").field("type", "date").field("format", "yyyy-MM-dd HH:mm:ss || yyyy-MM-dd HH:mm:ss.SSS || yyyy-MM-dd || yyyyMM").endObject();
                }
                xcb.endObject().endObject();
            }
            logger.debug("创建Type...");
            flag = getAdminClient().indices().preparePutMapping(indexName).setType(ELASTICSEARCH_TYPE).setSource(xcb.endObject().endObject().endObject()).get().isAcknowledged();  //通过es api创建索引
            logger.debug(flag ? "创建Type成功!" : "创建Type失败!");
            return flag;
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
            return false;
        }
    }

在这个地方,我使用了es的xContent去创建一个Mappng映射的json,然后遍历每个实体的数据项(就是字段),根据字段类型创建索引类型。

到了最后一步利用es的java api,通过setSource把mapping结构传递进去,我们的索引就基本创建成功了!

最后说一句,elasticsearch广泛运用于大数据实时查询中,是学大数据必不可少的一门框架技术,特别是es的聚合统计有利于数据计算和分析,希望大家可以多多了解交流

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java操作ES数据进行自定义排序,可以使用ES中的Function Score Query来实现,其中可以通过Script Score来自定义排序。 以下是一个示例代码,假设我们有一个索引名为"my_index",包含以下数据: ``` { "name": "John Smith", "age": 30, "score": 8.5 }, { "name": "Jane Doe", "age": 25, "score": 9.0 }, { "name": "Bob Johnson", "age": 35, "score": 7.5 } ``` 现在我们想要按照分数(score)和年龄(age)进行排序,其中分数的权重为0.7,年龄的权重为0.3。那么可以使用以下代码: ```java import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder; import org.elasticsearch.index.query.functionscore.ScriptScoreFunctionBuilder; import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptType; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.sort.FieldSortBuilder; import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortOrder; SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); Script sortScript = new Script(ScriptType.INLINE, "painless", "doc['score'].value * 0.7 + doc['age'].value * 0.3", null); ScriptScoreFunctionBuilder scriptScoreFunctionBuilder = new ScriptScoreFunctionBuilder(sortScript); FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(QueryBuilders.matchAllQuery(), scriptScoreFunctionBuilder); FieldSortBuilder scoreSortBuilder = SortBuilders.fieldSort("score") .order(SortOrder.DESC); FieldSortBuilder ageSortBuilder = SortBuilders.fieldSort("age") .order(SortOrder.DESC); searchSourceBuilder.query(functionScoreQueryBuilder) .sort(scoreSortBuilder) .sort(ageSortBuilder); SearchRequest searchRequest = new SearchRequest("my_index"); searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); ``` 在上面的代码中,我们使用Script Score来计算每个文档的得分,其中分数的权重为0.7,年龄的权重为0.3。然后使用Function Score Query将自定义的得分与其他查询条件结合起来,最后使用Field Sort来按照得分和年龄进行排序。最后执行搜索请求,将结果返回到searchResponse中。 需要注意的是,上面的示例代码中使用了Painless脚本语言来计算得分,如果需要使用其他脚本语言,请根据实际情况修改脚本语言类型和脚本内容。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值