试图从Java中数千个有模式偏差的JSON文件中提取数据



我有几千个JSON文件。它们中的大多数都可以有一个JSON数组,数组中有多达10000个元素。。。为了让事情变得更有趣,元素的数据结构可以因元素而异。。。有时,从范数到在每个元素中添加更多数组的偏差只有一个简单的单一属性偏差。但这是";项目";我需要从这些文件中提取的数组。

攻击这个问题的方法——在我的逻辑中——是首先从所有文件中提取每个不同的数据结构,这样我就可以理解当我试图获取数据时我要追求什么。如果我不能命名我想要的元素,那么我怎么能得到它们呢?尽管实际上可能有一种方法可以做到这一点,但我对JSON和GSON等方面的知识还不够,不知道该怎么做。

这将是我的第一个真正的JSON项目。。。我以前从未玩过JSON,所以我花了很多时间在谷歌上搜索和阅读,现在我完全理解JSON是如何工作的。。。我只是没有能力有效地使用它。在过去的几天里,我一直在研究这些文件,尽管我已经取得了一些进展,但我足够聪明,知道什么时候我需要以前做过这些工作的人的帮助。

这些示例不是从这些文件中剪切和粘贴的。为了简单起见,我使它们通用。但这是我迄今为止看到的一个文件与下一个文件结构差异的例子。第一个文件是迄今为止最常见的。。。其中";项目";数组将具有完全相同元素名称的静态结构,但在一个文件中会有10000个元素名称。。。而下一个文件不会那么干净。

我在这些文件中看到的最常见的JSON文件:

{
"employees" : [
{
"name": "John Doe"
},
{
"name": "Jane Doe"
}
],
"items": [
{
"item_name": "Goofy Widget",
"timestamp": 1616987224024,
"contents": "Some really nice goofy widgets",
"item_type": "Cleaning Widget",
"for_sale": false
},
{
"item_name": "Machine Widget",
"timestamp": 1616987218652,
"contents": "Hand held vaccuum",
"item_type": "Functional Widget",
"for_sale": false
}
],
"items_from_inventory": true,
"category_type": "Average",
"region_placement": "Northwest America"
}

在手动查看了几个文件后,有些文件可能是这样的,有时从一个完整的数组元素到下一个数组元素会有偏差:

{
"employees" : [
{
"name": "Jack Smith"
},
{
"name": "Joe Smith"
},
{
"name": "Jimmy Smalley"
}
],
"items": [
{
"item_name": "Sneakers",
"timestamp": 1616987224024,
"contents": "Plain white sneakers",
"item_type": "Foot Wear",
"for_sale": false
},
{
"item_name": "Personal T-Shirts",
"timestamp": 1616987224024,
"contents": "Color variety T-Shirts",
"color_options": [
{
"color1": "Red",
"color2": "Green",
"color3": "Black",
"color4": "White"
}
],
"item_classifications": [
{
"class1": "Weekend Use",
"class2": "Family Picnics",
"class3": "Casual Fridays"
},
],
"for_sale": false
},
{
"item_name": "Basketballs",
"timestamp": 1616987218652,
"contents": "Three quality basketballs",
"item_type": "Sport Items",
"brands": [
{
"brand1": ",Spalding",
"brand2": "Wilson"
},
],
"for_sale": false
}
],
"items_from_inventory": false,
"category_type": "Personal Use",
"region_placement": "North America"
}

这些文件的基本核心结构从一个文件到下一个文件是相当一致的,偏差似乎主要在";项目";数组,其中一些元素具有与其他元素不同的数据结构(我们在MySql世界中所知的模式)。

我一直在尝试GSON,因为它似乎很受欢迎,尽管我不关心我使用的库,但我只需要获取数据。

我决定从目前为止最常见的数组结构开始,这就是我想到的。以下是表示最常见的数组结构的类:

package widgets;
public class Widget {

public Widget(String itemName, long timestamp, String contents, String itemType, boolean forSale) {
this.itemName     = itemName;
this.timestamp    = timestamp;
this.contents     = contents;
this.itemType     = itemType;
this.forSale      = forSale;
}
private String             itemName;
private long               timestamp;
private String             contents;
private String             itemType;
private boolean            forSale;
public void setItemName(String itemName) { this.itemName = itemName;}
public void setTimestamp(long timestamp) { this.timestamp = timestamp;}
public void setContents(String contents) { this.contents = contents;}
public void setItemType(String itemType) { this.itemType = itemType;}
public void setForSale(boolean forSale)  { this.forSale = forSale;}
public String getItemName() { return itemName;}
public long getTimestamp()  { return timestamp;}
public String getContents() { return contents;}
public String getItemType() { return itemType;}
public boolean isForSale()  { return forSale;}
@Override
public String toString() {
return "senderName = " + this.itemName + "n" +
"timestamp = " + this.timestamp + "n" +
"content = " + this.contents + "n" +
"type = " + this.itemType + "n" +
"isUnsent = " + (this.forSale ? "true" : "false") + "n";
}
}

我有点想把它留在这里,而不是真正进入我成功和失败的地方,因为我真的不在乎我做错了什么,我只需要知道如何做对。。。这就是我想要的:

有人会告诉我如何从这些文件中提取所有Json结构定义吗;项目";要素

有人能告诉我如何正确地提取数据吗;项目";数组可以从一个元素到下一个元素不同吗?

我只需要一个以前来过这里的人,能给我指一条正确的路,这样我就不必走每一条路,转身往回走,然后再尝试另一条路。

我将非常感谢你的帮助。

谢谢你,

Mike Sims

要从JSON字符串中提取JSON数组,然后将JSONArray转换为Widget对象,可以执行以下操作:

JSONObject mainObj = new JSONObject(<full json string>);
JSONArray itemsArr = mainObj.getJSONArray("items");
ObjectMapper om = new ObjectMapper();
List<Widget> widgetList = objectMapper.readValue(itemsArr.toString(), new 
TypeReference<List<Widget>>(){});
// work with widgetList here

我建议使用更轻的重量和更交互式的东西来进行";形状";的数据。我的两个最佳选择是:

  • OpenRefine
  • jq

取决于您对交互式图形工具还是命令行工具更满意。两者都是开源和免费的,可以让你快速浏览你的数据集。

我已经意识到GSON的力量!

我最终弄清楚了如何将JSON数据映射到类。我开始浏览所有文件,并使用这样的方法提取每个元素名称:

private void getElements(String path){
try {
Reader reader = Files.newBufferedReader(Paths.get(path));
JsonObject jo = JsonParser.parseReader(reader).getAsJsonObject();
for (String key : jo.keySet()) {
System.out.println(key);
}
}
catch (IOException e) {e.printStackTrace();}
}

最终给了我:

employees
items
items_from_inventory
category_type
region_placement

我已经知道了,但该方法允许我验证每个文件在主元素方面是相同的。

然后,知道项是一个数组,我再次遍历每个文件,并使用这种方法从每个数组中获取元素,只是我决定不打印到控制台,而是创建一个数组列表,只有当每个数组的每个结构是唯一的时,才保存该结构:

private final List<LinkedList<String>> arraySets = new ArrayList<>();
private void getArrayElements(String path) {
try {
Reader reader = Files.newBufferedReader(Paths.get(path));
JsonObject jo = JsonParser.parseReader(reader).getAsJsonObject();
JsonArray ja = jo.getAsJsonArray("items");
int max = ja.size();
for (int x = 0; x < max; x++) {
JsonElement je = ja.set(x,ja.get(x));
JsonObject njo = je.getAsJsonObject();
LinkedList<String> arraySet = new LinkedList<>();
for(String key: njo.keySet()) {
arraySet.addLast(key);
}
if (!arraySets.contains(arraySet)) {
arraySets.add(arraySet);
}
}
}
catch (IOException e) { e.printStackTrace();}
}

以类似的方式,我遍历了数组中的每个数组,并提取了这些元素名称。

然后,我创建了一个主类,它有适合每个文件轮廓的变量,因为每个文件中都有完全相同的元素——当然,唯一的区别是每个";项目";数组中可能有不同的元素。

因此,整个文件的主类看起来像这样:

import Item;
import Employee;
import java.util.List;
public class Master {
private List<Employee> employees;
private List<Item>     items;
private boolean items_from_inventory;
private String category_type;
private String region_placement;
public List<Employee> getEmployees() {
return employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
public List<Item> getItems() {
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
public boolean isItems_from_inventory() {
return items_from_inventory;
}
public void setItems_from_inventory(boolean items_from_inventory) {
this.items_from_inventory = items_from_inventory;
}
public String getCategory_type() {
return category_type;
}
public void setCategory_type(String category_type) {
this.category_type = category_type;
}
public String getRegion_placement() {
return region_placement;
}
public void setRegion_placement(String region_placement) {
this.region_placement = region_placement;
}
}

然后Employee类看起来像这样:

public class Employee {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

Items类是类似的,只是它有额外的List变量,每个列表类型都是自己的类,这些类具有要映射到的数组的独立元素。我包括了Items数组中可能包含的所有数组。

然后我就这么做了:

Path         rootDir  = Paths.get(rootFolderString);
Stream<Path> paths    = Files.walk(rootDir);
List<Path>   pathList = paths.collect(Collectors.toList());
for (Path path : pathList) {
if (path.toFile().getAbsolutePath().endsWith("json")) {
String fileString = new String(Files.readAllBytes(path.toFile().getAbsolutePath()));
Master master = new Gson().fromJson(fileString,new TypeToken<Master>() {}.getType());
}
}

它像冠军一样发挥作用!

最新更新