如何用Java从Elasticsearch任务响应中提取无键节点ID?
从Elasticsearch任务响应中提取任务ID的Java实现方案
针对你需要从Elasticsearch运行任务响应JSON中提取类似ZKUuxQZpRCCcJ0njBM1P0A:118这类任务ID的需求,我整理了两种可行的实现方案:
方案1:使用Java JSON解析器(以Jackson为例)
你提到的动态键问题确实是个小难点,不过我们可以用Map结构来接收这些动态内容,不用硬编码响应类。这里以常用的Jackson库为例:
首先确保项目引入Jackson依赖(Maven示例):
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.2</version> </dependency>
然后编写解析代码:
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class EsTaskParser { public static void main(String[] args) throws IOException { String jsonResponse = "{ \"nodes\": { \"ZKUuxQZpRCCcJ0njBM1P0A\": { \"name\": \"ZKUuxQZ\", \"transport_address\": \"127.0.0.1:9300\", \"host\": \"127.0.0.1\", \"ip\": \"127.0.0.1:9300\", \"roles\": [ \"master\", \"data\", \"ingest\" ], \"tasks\": { \"ZKUuxQZpRCCcJ0njBM1P0A:118\": { \"node\": \"ZKUuxQZpRCCcJ0njBM1P0A\", \"id\": 118, \"type\": \"transport\", \"action\": \"indices:data/write/delete/byquery\", \"start_time_in_millis\": 1527808643421, \"running_time_in_nanos\": 154234724059, \"cancellable\": true, \"headers\": {} } } } } }"; ObjectMapper objectMapper = new ObjectMapper(); JsonNode rootNode = objectMapper.readTree(jsonResponse); JsonNode nodesNode = rootNode.get("nodes"); List<String> taskIds = new ArrayList<>(); // 遍历所有节点 nodesNode.fields().forEachRemaining(nodeEntry -> { JsonNode tasksNode = nodeEntry.getValue().get("tasks"); if (tasksNode != null && !tasksNode.isNull()) { // 遍历当前节点下的所有任务,键就是我们要的任务ID tasksNode.fields().forEachRemaining(taskEntry -> { taskIds.add(taskEntry.getKey()); }); } }); // 输出结果:["ZKUuxQZpRCCcJ0njBM1P0A:118"] System.out.println(taskIds); } }
这种方式的优势是精准匹配,不会受到JSON格式变动(比如空格、换行)的影响,比正则表达式更可靠。
方案2:使用正则表达式
你原来的正则已经基本可用,我帮你优化了一下,确保只匹配tasks对象下的键(也就是被双引号包裹的目标字符串),避免误匹配其他位置的类似格式内容:
import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; public class EsTaskRegexParser { public static void main(String[] args) { String jsonResponse = "{ \"nodes\": { \"ZKUuxQZpRCCcJ0njBM1P0A\": { \"name\": \"ZKUuxQZ\", \"transport_address\": \"127.0.0.1:9300\", \"host\": \"127.0.0.1\", \"ip\": \"127.0.0.1:9300\", \"roles\": [ \"master\", \"data\", \"ingest\" ], \"tasks\": { \"ZKUuxQZpRCCcJ0njBM1P0A:118\": { \"node\": \"ZKUuxQZpRCCcJ0njBM1P0A\", \"id\": 118, \"type\": \"transport\", \"action\": \"indices:data/write/delete/byquery\", \"start_time_in_millis\": 1527808643421, \"running_time_in_nanos\": 154234724059, \"cancellable\": true, \"headers\": {} } } } } }"; // 正则说明:匹配被双引号包裹的、由字母数字下划线短横线+冒号+数字组成的字符串 // 通过 (?<=tasks":\s*{) 确保只匹配tasks对象内的键 Pattern pattern = Pattern.compile("(?<=tasks\":\\s*{)\\s*\"([a-zA-Z0-9_-]+:[0-9]+)\""); Matcher matcher = pattern.matcher(jsonResponse); List<String> taskIds = new ArrayList<>(); while (matcher.find()) { taskIds.add(matcher.group(1)); } // 输出结果:["ZKUuxQZpRCCcJ0njBM1P0A:118"] System.out.println(taskIds); } }
如果JSON中tasks包含多个任务,这个正则也能全部匹配到。不过要注意,如果JSON的格式有较大变动(比如tasks的位置或结构变化),正则可能会失效,所以更推荐方案1。
内容的提问来源于stack exchange,提问作者Jinggang
相关产品推荐
相关产品推荐

