我有一個 JSON 結構中來自 ElasticSearch 的欄位映射串列。我需要將欄位中的鍵提取到一個name.value串列中以用作搜索詞。
例如,我從 ElasticSearch 得到的回應如下所示:
{
"orange": {
"type": "keyword"
},
"apple": {
"type": "keyword"
},
"banana": {
"type": "keyword"
},
"pineapple": {
"properties": {
"color": {
"type": "text"
},
"size": {
"type": "text"
}
}
},
"vegetables": {
"properties": {
"potato": {
"properties": {
"quality": {
"type": "keyword"
},
"price": {
"type": "keyword"
},
"location": {
"type": "keyword"
}
}
}
}
}
}
我需要把它轉換成一個串列
[
"orange",
"apple",
"banana",
"pineapple.color",
"pineapple.size",
"vegetables.potato.quality",
"vegetables.potato.price",
"vegetables.potato.location",
"vegetables.cabbage"
]
我對從哪里開始有點迷茫,所以無論“物件” “屬性”鍵最終有多深,我都會得到一些有用的東西。
編輯:
我有幾種方法我正在嘗試這樣做,但我一直以嵌套回圈結束
private static String process(final Map.Entry<String, Object> entry) {
final String fieldName = entry.getKey();
final Map<String, Object> value = toSourceMap(entry.getValue());
if (value.containsKey("properties")) {
final Map<String, Object> properties = toSourceMap(value.get("properties"));
process(entry); // ??
}
return fieldName;
}
我正在使用的一個小輔助方法將未知物件轉換為地圖
private static Map<String, Object> toSourceMap(final Object sourceMap) {
try {
final Map<String, Object> map = (Map) sourceMap;
return map;
} catch (final Exception e) {
return Map.of();
}
}
我打電話給這個
final List<String> fieldName = new ArrayList<>();
for (final Map.Entry<String, Object> entry : properties.entrySet()) {
fieldName.add(process(entry));
}
試圖從process方法中獲取每個值的串列
編輯2:
我可以得到一些適用于一層深度的東西,但這不會捕捉到更深層次的物體,比如vegetables.potato.quality
private static List<String> process(final Map.Entry<String, Object> entry) {
final String fieldName = entry.getKey();
final Map<String, Object> value = toSourceMap(entry.getValue());
final List<String> fields = new ArrayList<>();
if (value.containsKey("properties")) {
final Map<String, Object> properties = toSourceMap(value.get("properties"));
properties.keySet().stream().map(s -> fieldName "." s).forEach(fields::add);
} else {
fields.add(fieldName);
}
return fields;
}
和來電者
final List<String> fieldName = new ArrayList<>();
for (final Map.Entry<String, Object> entry : properties.entrySet()) {
fieldName.addAll(process(entry));
}
uj5u.com熱心網友回復:
我確信有一種更清潔、更好的方法來做到這一點,但我能夠通過執行以下操作來實作我所需要的
private static List<String> process(final Map.Entry<String, Object> entry) {
final String fieldName = entry.getKey();
final List<String> fields = new ArrayList<>();
final Map<String, Object> value = toSourceMap(entry.getValue());
if (value.containsKey(MAPPING_PROPERTIES)) {
toSourceMap(value.get(MAPPING_PROPERTIES)).entrySet()
.stream()
.map(FieldMappingFactory::process)
.map(nestedFields -> nestedFields.stream().map(f -> "%s.%s".formatted(fieldName, f)).toList())
.forEach(fields::addAll);
} else {
fields.add(fieldName);
}
return fields;
}
uj5u.com熱心網友回復:
這是一個基于深度優先搜索樹遍歷演算法的解決方案。
由于它是迭代的,因此您可以使用它來處理甚至深度嵌套的海量 JSON,而不會冒著獲得StackOverFlowError.
為了實作 DFS,我們需要一個 Stack 和一個 Map 來存盤與正在探索的節點關聯的路徑。
作為第一步,我們需要讀取整個 JSON 樹并JsonNode在堆疊上獲得。
然后,直到堆疊不為空,需要通過將其從堆疊中拉出來檢查它包含的每個節點。如果該節點恰好是ArrayNodeor ObjectNode,則應將其所有可以通過獲取的子節點JsonNode.fields()添加到堆疊中。
String json = // the source JSON
JsonNode node = new ObjectMapper().readTree(json);
List<String> results = new ArrayList<>();
Deque<JsonNode> stack = new ArrayDeque<>();
Map<JsonNode, List<String>> pathByNode = new HashMap<>();
pathByNode.put(node, Collections.emptyList());
Set<String> keysToExclude = Set.of("type", "properties"); // add more if you need
stack.push(node);
while (!stack.isEmpty()) {
JsonNode current = stack.pop();
List<String> path = pathByNode.get(current);
if (current instanceof ArrayNode || current instanceof ObjectNode) {
for (Iterator<Map.Entry<String, JsonNode>> it = current.fields(); it.hasNext(); ) {
Map.Entry<String, JsonNode> next = it.next();
stack.push(next.getValue());
String propertyName = next.getKey();
List<String> newPath;
if (!keysToExclude.contains(propertyName)) {
newPath = new ArrayList<>(path);
newPath.add(propertyName);
results.add(String.join(".", newPath)); // list of path should be updated
} else {
newPath = path;
}
pathByNode.put(next.getValue(), newPath);
}
}
}
results.forEach(System.out::println);
輸出:
orange
apple
banana
pineapple
vegetables
vegetables.potato
vegetables.potato.quality
vegetables.potato.price
vegetables.potato.location
pineapple.color
pineapple.size
uj5u.com熱心網友回復:
這是一個更簡單的解決方案。
private static void process(List<String> paths, String path, JsonNode node, Set<String> excludeKeys) {
if (node.isValueNode()) {
paths.add(path);
} else if (node.isObject()) {
node.fields().forEachRemaining(elem -> {
String key = excludeKeys.contains(elem.getKey()) ? path : (path == null ? "" : path ".") elem.getKey();
process(paths, key, elem.getValue(), excludeKeys);
});
} else { // This part is not required if there is no array inside the source JSON object
for (int i = 0; i < node.size(); i ) {
process(paths, String.format("%s[%d]", path, i), node.get(i), excludeKeys);
}
}
}
呼叫者
JsonNode node = new ObjectMapper().readTree(// JSON string //);
List<String> paths = new ArrayList<>();
process(paths, null, node, Set.of("properties", "type"));
paths.forEach(System.out::println);
輸出
orange
apple
banana
pineapple.color
pineapple.size
vegetables.potato.quality
vegetables.potato.price
vegetables.potato.location
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/520659.html
標籤:爪哇json递归杰克逊
上一篇:遞回如何在二叉樹中填充子樹值?
下一篇:按給定順序排名
