アマゾンAPIを活用した蔵書管理システム(3)

November 18, 2008 – 5:36 pm

前回までのエントリで、アマゾンAPIを利用して書籍データを取得する仕組みを整えることができた。いよいよ、アマゾンから取得した書籍データを我がサーバ上にデータベースとして取り込む方法について移る。データベース化にあたっては、以前のエントリ「MySQLを学習(1)」において学んだリレーショナルデータベースの利点を実際に体験することになる。

データベースの設計と構築: 私のようにDBMSの初心者にとって本格的なデータベースをいちから設計するというのは骨の折れる仕事だ。そこで、Web上で紹介されている蔵書データベースにどのようなものがあるか調べることから始めた。そこで見つけたのが、「蔵書インデキシングプロジェクト活動進捗(4)」に述べられている労作。なるほど、データベースの正規化というのはこのように行うのかと感心。ということで、ここで示されているデータベース構造を借用させていただいて、蔵書データベースとすることにした。(若干、我がほうに都合のよいように変更した部分もあるが、基本的な構造はquneさんのブログの記述を活用させていただいた。感謝)

DBテーブル作成用のSQL文は以下:

BookDB.sql:

DROP TABLE IF EXISTS book_author;
DROP TABLE IF EXISTS book;
DROP TABLE IF EXISTS publisher;
DROP TABLE IF EXISTS binding;
DROP TABLE IF EXISTS role;
DROP TABLE IF EXISTS currency;
DROP TABLE IF EXISTS author;

CREATE TABLE publisher (
  id INTEGER(8) PRIMARY KEY AUTO_INCREMENT,
  publisher VARCHAR(256) NOT NULL
);

CREATE TABLE binding (
  id INTEGER(8) PRIMARY KEY AUTO_INCREMENT,
  binding VARCHAR(64) NOT NULL
);

CREATE TABLE role (
  id INTEGER(8) PRIMARY KEY AUTO_INCREMENT,
  role VARCHAR(32) NOT NULL
);

CREATE TABLE currency (
  id INTEGER(8) PRIMARY KEY AUTO_INCREMENT,
  currency_cd CHAR(3) NOT NULL
);

CREATE TABLE author (
  id INTEGER(8) PRIMARY KEY AUTO_INCREMENT,
  author VARCHAR(64) NOT NULL
);

CREATE TABLE book (
  id INTEGER(8) PRIMARY KEY AUTO_INCREMENT,
  isbn CHAR(10),
  asin CHAR(10),
  ean CHAR(13),
  title VARCHAR(256) NOT NULL,
  image_url VARCHAR(128),
  pubdate DATE,
  price DECIMAL(10,2),
  pages INTEGER(6),
  publisher_id INTEGER(8),
  binding_id INTEGER(8),
  currency_id INTEGER(8)
);
ALTER TABLE book ADD FOREIGN KEY (publisher_id)
  REFERENCES publisher (id);
ALTER TABLE book ADD FOREIGN KEY (binding_id)
  REFERENCES binding (id);
ALTER TABLE book ADD FOREIGN KEY (currency_id)
  REFERENCES currency (id);

CREATE TABLE book_author (
  id INTEGER(8) PRIMARY KEY AUTO_INCREMENT,
  book_id INTEGER(8) NOT NULL,
  author_id INTEGER(8) NOT NULL,
  role_id INTEGER(8)
);
ALTER TABLE book_author ADD FOREIGN KEY (book_id)
  REFERENCES book (id);
ALTER TABLE book_author ADD FOREIGN KEY (author_id)
  REFERENCES author (id);
ALTER TABLE book_author ADD FOREIGN KEY (role_id)
  REFERENCES role (id)
        

データベース作成の手続き: ここで示したSQL文に基づきデータベース作成の手続きを示すことにしよう。なお、データベース作成手順については、既に我がブログの以前のエントリー「MySQLを学習(2):DataBaseとTableの作成」において記述しており、これと重複する部分があることをお断りしておく。

まず、「蔵書管理システム」用の空のデータベースSampleDBを作成する:

# mysql -u username -p
Enter password: password
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 9994
Server version: 5.0.45 Source distribution

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql> create database sampleDB;
Query OK, 1 row affected (0.00 sec)
        

このDB上に、既に述べたBookDB.sql で定義した複数のテーブルを一括して作成する:

# mysql -u username -p SampleDB < BookDB.sql;
Enter password: password
        

これで、データベースSampleDBの枠組みが出来上がったはずだ。実際に、テーブルが問題なく作成されていることを確かめてみよう;

# mysql -u username -p SampleDB
Enter password: password

mysql> show tables;
+--------------------+
| Tables_in_SampleDB |
+--------------------+
| author             |
| binding            |
| book               |
| book_author        |
| currency           |
| publisher          |
| role               |
+--------------------+
7 rows in set (0.00 sec)

mysql> describe book;
+--------------+---------------+------+-----+---------+----------------+
| Field        | Type          | Null | Key | Default | Extra          |
+--------------+---------------+------+-----+---------+----------------+
| id           | int(8)        | NO   | PRI | NULL    | auto_increment |
| isbn         | char(10)      | YES  |     | NULL    |                |
| asin         | char(10)      | YES  |     | NULL    |                |
| ean          | char(13)      | YES  |     | NULL    |                |
| title        | varchar(256)  | NO   |     |         |                |
| image_url    | varchar(128)  | YES  |     | NULL    |                |
| pubdate      | date          | YES  |     | NULL    |                |
| price        | decimal(10,2) | YES  |     | NULL    |                |
| pages        | int(6)        | YES  |     | NULL    |                |
| publisher_id | int(8)        | YES  | MUL | NULL    |                |
| binding_id   | int(8)        | YES  | MUL | NULL    |                |
| currency_id  | int(8)        | YES  | MUL | NULL    |                |
+--------------+---------------+------+-----+---------+----------------+
12 rows in set (0.00 sec)

mysql> describe author;
+--------+-------------+------+-----+---------+----------------+
| Field  | Type        | Null | Key | Default | Extra          |
+--------+-------------+------+-----+---------+----------------+
| id     | int(8)      | NO   | PRI | NULL    | auto_increment |
| author | varchar(64) | NO   |     |         |                |
+--------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

mysql> describe book_author;
+-----------+--------+------+-----+---------+----------------+
| Field     | Type   | Null | Key | Default | Extra          |
+-----------+--------+------+-----+---------+----------------+
| id        | int(8) | NO   | PRI | NULL    | auto_increment |
| book_id   | int(8) | NO   | MUL |         |                |
| author_id | int(8) | NO   | MUL |         |                |
| role_id   | int(8) | YES  | MUL | NULL    |                |
+-----------+--------+------+-----+---------+----------------+

mysql> quit;
Bye
        

書籍データのデータベース上への反映: データベースの枠組みが完成したところで、前回のエントリーで紹介した方式で取得する書籍データを、このデータベース上に反映させなければならない。前回説明したように、取得データは、個々の書籍について2種類のデータオブジェクト(DTO形式:Book、Author_array)で得られる。次の作業は、これらDTO形式のデータを上記したSQLデータベースSampleDBに取り込むための仕組みを作成することになる。

SampleDBへのデータの取り込みを行うため、Daoオブジェクト(BookDao)を作成し、このなかに、新規の書籍データを取り込むためのメソッドinsertBook()を作成した。BookDaoのphpソースは最後に掲げることにし、実際に、これを用いて書籍データをデータベースに登録する手続きをサンプルとして以下にしめしてみよう:

サンプルでは、前回のエントリーで取り扱った本「利己的な遺伝子」をデータベース上に取り込むことにする。そのためのSample.phpを作成する:

Sample.php

<?php
      require_once("SetBookByBookID.php");
      require_once("BookDao.php");

      $BOOK_ID  = '4314005564';
      $BookCode = 'ISBN';
      $rtn          = SetBookByBookID($BOOK_ID, $BookCode);
      $book         = $rtn[0];
      $author_array = $rtn[1];

      $bookdao = new BookDao();
      $bookdao->insertBook($book, $author_array);
      $book         = NULL;
      $author_array = NULL;
      $bookdao      = NULL;
?>
        

このphpスクリプトでは、まず前回作成したSetBookByBookID()を用いて書籍データを二つのデータオブジェクト$bookと$author_arrayで取得する。このデータを新たに作成したクラスBookDaoのメソッドinsertBook()の引数とし、これによりSampleDB上に反映している。

この方法で9冊の書籍を、逐次、データベースSampleDB上に取り込み、SampleDB上にデータが正しくとりこまれていることを確認してみた。

mysql> select id, title from book;
+----+-----------------------------------------------------------------------------------------------+
| id | title                                                                                         |
+----+-----------------------------------------------------------------------------------------------+
|  1 | 利己的な遺伝子 (科学選書)                                                                     |
|  2 | 盲目の時計職人                                                                                |
|  3 | はじめての年金・医療保険―保険の基本は社会保険から (集英社新書)                                |
|  4 | 科学者の新しい役割 (双書科学/技術のゆくえ)                                                    |
|  5 | 第二種基礎研究                                                                                |
|  6 | 免疫の意味論                                                                                  |
|  7 | 公共のための科学技術                                                                          |
|  8 | 生態学的視覚論―ヒトの知覚世界を探る                                                           |
|  9 | 「病気」の誕生―近代医療の起源 (平凡社選書)                                                    |
+----+-----------------------------------------------------------------------------------------------+
9 rows in set (0.00 sec)

mysql> select id, author from author;
+----+-----------------------------------+
| id | author                            |
+----+-----------------------------------+
|  1 | リチャード・ドーキンス            |
|  2 | 日高 敏隆                         |
|  3 | 岸 由二                           |
|  4 | 羽田 節子                         |
|  5 | 垂水 雄二                         |
|  6 | 児玉 美穂                         |
|  7 | 吉川 弘之                         |
|  8 | 内藤 耕                           |
|  9 | 多田 富雄                         |
| 10 | 小林 伝司                         |
| 11 | J.J.ギブソン                      |
| 12 | 古崎 敬                           |
| 13 | 児玉 善仁                         |
+----+-----------------------------------+
13 rows in set (0.00 sec)

mysql> select id, role from role;
+----+--------+
| id | role   |
+----+--------+
|  1 |        |
|  2 | 翻訳   |
|  3 | 編集   |
+----+--------+
3 rows in set (0.00 sec)

mysql> select * from book_author;
+----+---------+-----------+---------+
| id | book_id | author_id | role_id |
+----+---------+-----------+---------+
|  1 |       1 |         1 |       1 |
|  2 |       1 |         2 |       2 |
|  3 |       1 |         3 |       2 |
|  4 |       1 |         4 |       2 |
|  5 |       1 |         5 |       2 |
|  6 |       2 |         1 |       1 |
|  7 |       2 |         2 |       2 |
|  8 |       3 |         6 |       1 |
|  9 |       4 |         7 |       1 |
| 10 |       5 |         7 |       1 |
| 11 |       5 |         8 |       1 |
| 12 |       6 |         9 |       1 |
| 13 |       7 |        10 |       3 |
| 14 |       8 |        11 |       1 |
| 15 |       8 |        12 |       1 |
| 16 |       9 |        13 |       1 |
+----+---------+-----------+---------+
16 rows in set (0.00 sec)

mysql> select id, publisher from publisher;
+----+-----------------------+
| id | publisher             |
+----+-----------------------+
|  1 | 紀伊國屋書店          |
|  2 | 早川書房              |
|  3 | 集英社                |
|  4 | 岩波書店              |
|  5 | 日経BP社              |
|  6 | 青土社                |
|  7 | 玉川大学出版部        |
|  8 | サイエンス社          |
|  9 | 平凡社                |
+----+-----------------------+
9 rows in set (0.00 sec)
        

テーブル上に書き込まれたデータが想定した通りデータベース上にあることが確認される。なお、アマゾンの書籍データベースへのアクセスは1秒に1回の制限があることから、アマゾンからの書籍データ取り込み用関数SetBookByBookID()を使用する際に注意したい。

さて、これでデータベースへの書籍データの取り込みは行うことができた。次回は、今回作成したSampleDBからのデータのk検索など、その操作方法についてみることにしよう。

BookDao.php:

<?php
Class BookDao {
        private $mysqli = null;
        //Constructor
        function __constructor() {
           $this->connect();
        }

        //Destructor
        function __destruct() {
           $this->disconnect();
        }

        //Connect to MySQL server
        private function connect() {
           if(is_null($this->mysqli)) {
               $this->mysqli = new mysqli("localhost", "user_name", "password", "SampleDB");
               $this->mysqli->query("SET NAMES utf8");
               if(mysqli_connect_errno()) {
                    die("Failed to connect to MySQL server<br></br> Reason:" . mysqli_connect_error());
               }
           }
        }
        //Disconnect from MySQL server
        private function disconnect() {
           is_null($this->mysqli) or $this->mysqli->close();
        }

// Register New Book_Data for tables
        public function insertBook( $book, $author_array ) {
           is_null($this->mysqli) and $this->connect();
        // check book to be registered in Table Book
           $sql = "SELECT id FROM book WHERE asin='". $book->getAsin() . "'";
           $result = $this->mysqli->query($sql);
           if ( $result->num_rows != 0 ) {
              $row = $result->fetch_array(MYSQLI_ASSOC);
              echo "This book is already registered! \n";
              $book_id = $row["id"];
              echo "book_id registered = " . $book_id . "\n" ;
           }
           else {
                // Set publisher table and publisher_id
                $sql = "SELECT id FROM publisher WHERE publisher='" . $book->getPublisher() . "'";
                $result = $this->mysqli->query($sql);
                if ( $result->num_rows == 0 ) {
                        $sql = "INSERT INTO publisher values('',
                                '" . $book->getPublisher() . "')";
                        if (!$this->mysqli->query($sql)) {
                                print "Failed to register(1002) " . $this->mysqli->error . "\n";
                        }
                        else {
                             $publisher_id = $this->mysqli->insert_id;
                        }
                }
                else {
                      $row = $result->fetch_array(MYSQLI_ASSOC);
                      $publisher_id = $row["id"];
                }
                // Set binding table and binding_id
                $sql = "SELECT id FROM binding WHERE binding='" . $book->getBinding() . "'";
                $result = $this->mysqli->query($sql);
                if ( $result->num_rows==0 ) {
                        $sql = "INSERT INTO binding values('',
                                '" . $book->getBinding() . "')";
                        if (!$this->mysqli->query($sql)) {
                                 print "Failed to register(1003) " . $this->mysqli->error . "\n";
                        }
                        else {
                             $binding_id = $this->mysqli->insert_id;
                        }
                }
                else {
                       $row = $result->fetch_array(MYSQLI_ASSOC);
                       $binding_id = $row["id"];
                }
                // Set currency table and currency_id
                $sql = "SELECT id FROM currency WHERE currency_cd='" . $book->getCurrency_cd() ."'";
                $result = $this->mysqli->query($sql);
                if ( $result->num_rows == 0 ) {
                         $sql = "INSERT INTO currency VALUES('',
                               '" . $book->getCurrency_cd() . "')";
                         if (!$this->mysqli->query($sql)) {
                               print "Failed to register(1004) " . $this->mysqli->errro . "\n";
                         }
                         else {
                              $currency_id = $this->mysqli->insert_id;
                         }
                }
                else {
                         $row = $result->fetch_array(MYSQLI_ASSOC);
                         $currency_id = $row["id"];
                }
                // Set Book Table for new data
                $sql = "INSERT INTO book values('',
                               '" . $book->getIsbn() . "',
                               '" . $book->getAsin() . "',
                               '" . $book->getEan() . "',
                               '" . $book->getTitle() . "',
                               '" . $book->getImage_url() . "',
                               '" . $book->getPubdate() . "',
                               '" . $book->getPrice() . "',
                               '" . $book->getPages() . "',
                               '" . $publisher_id . "',
                               '" . $binding_id . "',
                               '" . $currency_id . "')";
                if( !$this->mysqli->query($sql) ) {
                        print "Failed to register(1005) " . $this->mysqli->error . "\n";
                }
                else {
                        $book_id = $this->mysqli->insert_id;
                }
                // Set Author Table for new data
                for ( $i=0;  $i<sizeof($author_array); $i++) {
                      $sql = "SELECT id FROM author where author='" . $author_array[$i]->getAuthor() . "'";
                      $result = $this->mysqli->query($sql);
                      if ( $result->num_rows == 0 ) {
                          $sql = "INSERT INTO author values('',
                                '" . $author_array[$i]->getAuthor() . "')";
                          if(!$this->mysqli->query($sql)) {
                               print "Failed to register(1006) " . $this->mysqli->error . "\n";
                          }
                          else {
                               $author_id = $this->mysqli->insert_id;
                          }
                      }
                      else {
                          $row = $result->fetch_array(MYSQLI_ASSOC);
                          $author_id = $row["id"];
                      }
                      $sql = "SELECT id FROM role where role='" . $author_array[$i]->getRole() . "'";
                      $result = $this->mysqli->query($sql);
                      if ( $result->num_rows == 0 ) {
                          $sql = "INSERT INTO role values('',
                                '" . $author_array[$i]->getRole() . "')";
                          if(!$this->mysqli->query($sql)) {
                               print "Failed to register(1007) " . $this->mysqli->error . "\n";
                          }
                          else {
                               $role_id = $this->mysqli->insert_id;
                          }
                      }
                      else {
                          $row = $result->fetch_array(MYSQLI_ASSOC);
                          $role_id = $row["id"];
                      }
                      $sql = "INSERT INTO book_author values('',
                               '" . $book_id . "','" . $author_id . "','" . $role_id . "')";
                      if( !$this->mysqli->query($sql) ) {
                              print "Failed to register(1008) " . $this->mysqli->error . "\n";
                      }
                }
          }
      }
}
?>
        


  1. 1 Trackback(s)

  2. Nov 22, 2008: アマゾンAPIを活用した蔵書管理システム(4) | Yama's Memorandum

Post a Comment