2011-01-05 41 views
9

"Thật là hấp dẫn, nếu công cụ duy nhất bạn có là một cái búa, để đối xử với mọi thứ như thể nó là móng tay." - Abraham MaslowCơ sở dữ liệu Lập trình chức năng ở Clojure

Tôi cần phải viết một công cụ để kết xuất một cơ sở dữ liệu phân cấp lớn (SQL) sang XML. Hệ thống phân cấp bao gồm một bảng Person với các bảng phụ trợ Address, Phone, v.v.

  • tôi phải đổ ngàn hàng, vì vậy tôi muốn làm như vậy từng bước và không giữ các tập tin toàn bộ XML trong bộ nhớ.

  • Tôi muốn tách mã chức năng không thuần túy thành một phần nhỏ của ứng dụng.

  • Tôi nghĩ rằng đây có thể là cơ hội tốt để khám phá FP và đồng thời trong Clojure. Tôi cũng có thể cho thấy những lợi ích của dữ liệu bất biến và sử dụng đa lõi cho những người đồng nghiệp hoài nghi của tôi.

Tôi không chắc cấu trúc tổng thể của ứng dụng nên như thế nào. Tôi nghĩ rằng tôi có thể sử dụng một hàm không tinh khiết để lấy ra các hàng của cơ sở dữ liệu và trả về một chuỗi lười biếng mà sau đó có thể được xử lý bằng một hàm thuần túy trả về một đoạn XML.

Đối với mỗi hàng Person, tôi có thể tạo Future và có một số xử lý song song (thứ tự đầu ra không quan trọng).

Khi mỗi Person được xử lý, tác vụ sẽ truy xuất các hàng thích hợp từ các bảng Address, Phone, v.v ... và tạo XML lồng nhau.

Tôi có thể sử dụng hàm chung để xử lý hầu hết các bảng, dựa vào siêu dữ liệu của cơ sở dữ liệu để lấy thông tin cột, với các hàm đặc biệt cho vài bảng cần xử lý tùy chỉnh. Các hàm này có thể được liệt kê trong một map(table name -> function).

Tôi có thực hiện việc này đúng cách không? Tôi có thể dễ dàng quay trở lại để làm điều đó trong OO bằng cách sử dụng Java, nhưng điều đó sẽ không vui.

BTW, có sách hay nào về các mẫu hoặc kiến ​​trúc FP không? Tôi có một vài cuốn sách hay về Clojure, Scala và F #, nhưng mặc dù mỗi cuốn sách đều có ngôn ngữ tốt, nhưng không ai nhìn vào "bức tranh lớn" về thiết kế lập trình hàm.

+3

Theo hiểu biết của tôi, không có cuốn sách "FP cho kiến ​​trúc sư". Tuy nhiên, nếu bạn đọc "Cấu trúc dữ liệu thuần túy về chức năng" kết thúc, bạn chắc chắn sẽ có ý tưởng tốt hơn về cách áp dụng các khái niệm FP trong thế giới thực. Xem http://www.amazon.com/Purely-Functional-Structures-Chris-Okasaki/dp/0521663504 –

+0

@ Chris Smith: Tôi có cái đó trên danh sách mong muốn Amazon của tôi. Tôi sẽ kiểm tra. – Ralph

Trả lời

6

Ok, tuyệt, bạn đang sử dụng cơ hội này để hiển thị Clojure. Vì vậy, bạn muốn chứng minh FP và đồng thời. Roger đó.

Để wow interlocutors của bạn tôi sẽ làm cho một điểm để chứng minh:

  • Thực hiện chương trình của bạn sử dụng một chủ đề duy nhất.
  • Cách hiệu suất của chương trình tăng lên khi bạn tăng số lượng chuỗi.
  • Cách dễ dàng để đưa chương trình của bạn từ một đến nhiều luồng.

Bạn có thể tạo một hàm để kết xuất một bảng vào một tệp XML.

(defn table-to-xml [name] ...) 

Với điều đó, bạn có thể làm việc toàn bộ hoặc mã của bạn để chuyển đổi dữ liệu quan hệ thành XML.

Bây giờ bạn đã giải quyết được vấn đề cốt lõi, xem liệu việc ném nhiều chuỗi hơn vào nó sẽ làm tăng tốc độ của bạn hay không.

Bạn có thể sửa đổi table-to-xml để chấp nhận một tham số bổ sung:

(defn table-to-xml [name thread-count] ...) 

Điều này có nghĩa rằng bạn có đề làm việc trên một bảng n. Trong trường hợp này, mỗi luồng có thể xử lý mọi hàng thứ n. Một vấn đề với việc đặt nhiều luồng trên một bảng là mỗi luồng sẽ muốn ghi vào cùng một tệp XML. Nút cổ chai đó có thể làm cho chiến lược vô dụng, nhưng nó đáng để bắn.

Nếu tạo một tệp XML trên mỗi bảng có thể chấp nhận được thì việc sinh ra một chuỗi trên mỗi bảng có thể sẽ là một chiến thắng dễ dàng.

(map #(future (table-to-xml %)) (table-names)) 

Sử dụng chỉ là một mối quan hệ một-một giữa các bảng, các file và chủ đề: làm kim chỉ nam, tôi mong chờ mã của bạn để không chứa bất kỳ refs hoặc dosyncs và giải pháp nên được khá thẳng về phía trước.

Khi bạn bắt đầu sinh sản nhiều chủ đề cho mỗi bảng, bạn sẽ thêm độ phức tạp và có thể không thấy nhiều sự gia tăng hiệu suất.

Trong mọi trường hợp, bạn có thể có một hoặc hai truy vấn trên mỗi bảng để nhận giá trị và siêu dữ liệu. Về nhận xét của bạn về việc không muốn tải tất cả dữ liệu trong bộ nhớ: Mỗi chuỗi sẽ chỉ xử lý một hàng tại một thời điểm.

Hy vọng điều đó sẽ hữu ích!

Với nhận xét của bạn ở đây là một số mã pseudo-ish có thể giúp:

(defn write-to-xml [person] 
    (dosync 
    (with-out-append-writer *path* 
    (print-person-as-xml)))) 

(defn resolve-relation [person table-name one-or-many] 
    (let [result (query table-name (:id person))] 
    (assoc person table-name (if (= :many one-or-many) 
           result 
           (first result))))) 

(defn person-to-xml [person] 
    (write-to-xml 
    (-> person 
     (resolve-relation "phones" :many) 
     (resolve-relation "addresses" :many)))) 

(defn get-people [] 
    (map convert-to-map (query-db ...))) 

(defn people-to-xml [] 
    (map (fn [person] 
     (future (person-to-xml %))) 
     (get-people))) 

Bạn có thể xem xét sử dụng Chấp hành viên Java thư viện để tạo ra một hồ bơi thread.

+0

Tôi đã nghĩ đến việc phát ra phần tử gốc của XML ('người'), sau đó truy vấn cơ sở dữ liệu cho tất cả các hàng của người và bắt đầu một' Tương lai' riêng biệt cho mỗi hàng. Mỗi 'Tương lai 'sẽ chịu trách nhiệm truy vấn các bảng khác và tạo ra các phần tử XML lồng nhau (' địa chỉ', 'điện thoại', v.v.) rồi cuối cùng trả về đoạn' người' hoàn chỉnh. Vấn đề lớn hơn tôi có là làm thế nào để giữ cho hầu hết các chức năng "tinh khiết". Sử dụng các hàm bậc cao hơn có thể cho phép tôi thực hiện việc tương đương với "Inversion-of-Control" của FP. – Ralph

+0

Gotcha. Tôi sẽ cập nhật câu trả lời của mình để đưa ra một số đề xuất khác. – Psyllo

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