2012-02-22 34 views
27

Tôi đang cố gắng phân tích cú pháp một tệp JSON lớn (như http://eu.battle.net/auction-data/258993a3c6b974ef3e6f22ea6f822720/auctions.json) bằng thư viện gson (http://code.google.com/p/google-gson/) trong JAVA.JAVA - Cách tiếp cận tốt nhất để phân tích cú pháp tệp JSON cực lớn (cực lớn)

Tôi muốn biết sự chấp thuận tốt nhất để phân tích loại tệp lớn này (khoảng 80k dòng) và nếu bạn có thể biết API tốt có thể giúp tôi xử lý điều này. dòng

Một số ý tưởng ...

  1. đọc bởi dòng và thoát khỏi các định dạng JSON: nhưng đó là vô nghĩa.
  2. giảm tệp JSON bằng cách chia nhỏ tệp này thành nhiều tệp khác: nhưng tôi không tìm thấy bất kỳ API Java nào tốt cho việc này.
  3. sử dụng tệp này trực tiếp dưới dạng cơ sở dữ liệu nonSql, giữ tệp và sử dụng nó làm cơ sở dữ liệu của tôi.

Tôi thực sự sẽ đánh giá cao các quảng cáo/trợ giúp/tin nhắn/:-) Cảm ơn bạn.

+0

Giải pháp thay thế Java EE: javax.json.stream.JsonParser – xonya

Trả lời

27

Bạn không cần chuyển sang Jackson. Gson 2.1 đã giới thiệu giao diện TypeAdapter mới cho phép nối tiếp chuỗi và phát trực tuyến cây và trộn lẫn.

API hiệu quả và linh hoạt. Xem Gson's Streaming doc để biết ví dụ về kết hợp cây và ràng buộc chế độ. Điều này hoàn toàn tốt hơn so với chế độ trộn lẫn chế độ cây hỗn hợp; với ràng buộc bạn không lãng phí bộ nhớ xây dựng một đại diện trung gian của các giá trị của bạn.

Giống như Jackson, Gson có API đệ quy bỏ qua một giá trị không mong muốn; Gson gọi số này skipValue().

+0

Tôi sẽ kiểm tra này ra! Cảm ơn bạn đã chia sẻ – Dax

+0

Có một ví dụ hay về việc sử dụng 'TypeAdapter' để phân tích luồng hỗn hợp thành phân tích cú pháp cây không? Tôi có một trường hợp mà tôi muốn trộn nó vào một Danh sách các đối tượng rất lớn. Ví dụ trong tài liệu là luồng phân tích cú pháp một Danh sách 'Thư' nhưng nó không cho thấy cách bạn sẽ buộc trình phân tích luồng đó vào một trình phân tích cú pháp cây. (Nó cho thấy cách bạn buộc một trình phân tích cú pháp cây vào trình phân tích luồng) –

+0

Ví dụ: Tôi có 'CustomType' để xác định ánh xạ đối tượng và' CustomTypes mở rộng ArrayList '. Tôi tạo một 'TypeAdapter ' sử dụng ánh xạ đối tượng cho mỗi 'CustomType', nhưng chỉ trả về một danh sách rỗng ở cuối để tránh lưu toàn bộ danh sách trong bộ nhớ (ghi chúng vào cơ sở dữ liệu thay thế). Và sau đó đối tượng chứa được phân tích cú pháp đơn giản bằng cách sử dụng ánh xạ đối tượng. –

25

Tôi sẽ đề nghị xem Jackson Api rất dễ dàng để kết hợp các tùy chọn phân tích cú pháp luồng và mô hình cây: bạn có thể di chuyển toàn bộ tệp theo cách phát trực tuyến rồi đọc từng đối tượng vào một cây kết cấu.

Là một example, chúng ta hãy đầu vào sau:

{ 
    "records": [ 
    {"field1": "aaaaa", "bbbb": "ccccc"}, 
    {"field2": "aaa", "bbb": "ccc"} 
    ] , 
    "special message": "hello, world!" 
} 

Chỉ cần tưởng tượng các lĩnh vực là thưa thớt hoặc các hồ sơ có một cấu trúc phức tạp hơn.

Đoạn mã sau đây minh họa cách có thể đọc tệp này bằng cách kết hợp phân tích luồng và mô hình cây. Mỗi bản ghi riêng lẻ được đọc trong cấu trúc cây, nhưng tệp này không bao giờ được đọc toàn bộ vào bộ nhớ, làm cho nó có thể xử lý các tệp JSON có kích thước gigabyte trong khi sử dụng bộ nhớ tối thiểu.

import org.codehaus.jackson.map.*; 
    import org.codehaus.jackson.*; 
    import java.io.File; 
    public class ParseJsonSample { 
     public static void main(String[] args) throws Exception { 
     JsonFactory f = new MappingJsonFactory(); 
     JsonParser jp = f.createJsonParser(new File(args[0])); 
     JsonToken current; 
     current = jp.nextToken(); 
     if (current != JsonToken.START_OBJECT) { 
      System.out.println("Error: root should be object: quiting."); 
      return; 
     } 
     while (jp.nextToken() != JsonToken.END_OBJECT) { 
      String fieldName = jp.getCurrentName(); 
      // move from field name to field value 
      current = jp.nextToken(); 
      if (fieldName.equals("records")) { 
      if (current == JsonToken.START_ARRAY) { 
       // For each of the records in the array 
       while (jp.nextToken() != JsonToken.END_ARRAY) { 
       // read the record into a tree model, 
       // this moves the parsing position to the end of it 
       JsonNode node = jp.readValueAsTree(); 
       // And now we have random access to everything in the object 
       System.out.println("field1: " + node.get("field1").getValueAsText()); 
       System.out.println("field2: " + node.get("field2").getValueAsText()); 
       } 
      } else { 
       System.out.println("Error: records should be an array: skipping."); 
       jp.skipChildren(); 
      } 
      } else { 
      System.out.println("Unprocessed property: " + fieldName); 
      jp.skipChildren(); 
      } 
     }     
     } 
    } 

Như bạn có thể đoán, các nextToken() gọi mỗi lần cung cấp cho các sự kiện phân tích tiếp theo: bắt đầu đối tượng, bắt đầu lĩnh vực, bắt đầu mảng, bắt đầu đối tượng, ..., đối tượng cuối, ..., mảng cuối , ...

Cuộc gọi jp.readValueAsTree() cho phép đọc nội dung ở vị trí phân tích cú pháp hiện tại, đối tượng hoặc mảng JSON, thành mô hình cây JSON chung của Jackson. Khi bạn có điều này, bạn có thể truy cập dữ liệu ngẫu nhiên, bất kể thứ tự xuất hiện trong tệp (trong ví dụ field1 và field2 không phải lúc nào cũng theo thứ tự). Jackson cũng hỗ trợ ánh xạ lên các đối tượng Java của riêng bạn. Các jp.skipChildren() là thuận tiện: nó cho phép bỏ qua một cây đối tượng hoàn chỉnh hoặc một mảng mà không cần phải chạy cho mình trên tất cả các sự kiện chứa trong nó.

+0

Mã của bạn thực sự hữu ích! Tôi trang bị nó cho vấn đề của tôi và cuối cùng có thể thoát khỏi các trường hợp ngoại lệ không gian heap của tôi bởi vì tôi đọc các tập tin trong một đi trước :-) –

Các vấn đề liên quan