3
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

Kindle Library の蔵書をAlgoliaで検索する

これは何

Kindleの蔵書一覧を全文検索サービスのAlgoliaで検索可能にするスクリプトです。
こちらの記事を参考に、蔵書一覧をCSV出力する代わりに Algolia でインデックスし、検索可能にしてみます。

InstantSearch.jsでフロントエンドを作ると簡単なWebアプリケーションにもなります(サンプル)。

anime.gif

前提条件

あらかじめAlgoliaアカウントを作成し、API Keyを取得する必要があります。
アカウントの取得についてはこちらを参考に。
今回必要なのはインデックスを作成する権限及びレコードを追加する権限となるのため、editSettings と addObject 権限に絞った API キーをあらかじめ発行しておくと良いです。

Algolia Dashboard からの操作だと以下のように新規 API キー作成時に ACL を指定することができます。ACL など API キーに関する詳細はこちらの記事にまとまっています。

api_key.png

なお、Algoliaのフリープランでは10000レコード・10000検索リクエストまで無料なので、個人使用の範囲であればほぼ問題ないかと思います(ライブラリが10000冊を超える方ってどのくらいいるんだろう・・・)。

やり方

  • Kindle Cloud Readerにアクセス。本が大量にあると読み込みが終わるまで時間がかかるためしばらく待つ

  • F12を押して、デベロッパーツールを立ち上げる

  • Consoleタブに移動して、以下のコードの各変数を環境に合わせて変更し実行する。appIdとapiKeyはAlgoliaアカウント情報から取得したものを、indexNameは任意のものを指定する

let appId = 'YOUR_ALGOLIA_APP_ID'
let apiKey = 'YOUR_ALGOLIA_API_KEY_WITH_WRITE_PERMISSION'
let indexName = 'kindleLibrary'
  • 以下のコードを実行しインデックスを作成する

createAlgoliaIndex = function (appId, apiKey, indexName) {
    const url = `https://${appId}-dsn.algolia.net/1/indexes/${indexName}/settings`
    const headers = {
        'X-Algolia-API-Key': apiKey,
        'X-Algolia-Application-Id': appId
    }

    let req = new Request(url, {
        method: 'PUT',
        body: JSON.stringify({
            searchableAttributes: ["title", "authors", "purchaseDate"],
            customRanking: ["desc(purchaseDate)"],
            attributesForFaceting: ["searchable(authors)"]
        }),
        headers: headers
    })

    fetch(req)
        .then(response => {
            if (response.status === 200) {
                console.log(response.json());
            } else {
                throw new Error('Something went wrong on api server!' + response.json());
            }
        })
        .then(response => {
            console.debug(response);
        }).catch(error => {
            console.error(error);
        });
}

createAlgoliaIndex(appId, apiKey, indexName)
  • 以下のコードを実行しkindle libraryのデータをAlogliaに登録する

sendKindleToAlgolia = function (appId, apiKey, indexName) {
    let db = openDatabase('K4W', '3', 'thedatabase', 1024 * 1024);

    const url = `https://${appId}-dsn.algolia.net/1/indexes/${indexName}/batch`
    const headers = {
        'X-Algolia-API-Key': apiKey,
        'X-Algolia-Application-Id': appId
    }

    db.transaction(function (tx) {
        tx.executeSql('SELECT * FROM bookdata order by title;', [], function (tx, results) {
            const len = results.rows.length;
            let batch = []

            for (i = 0; i < len; i++) {
                let result = results.rows.item(i);
                let asin = result.asin;
                let title = result.title;
                let authors = JSON.parse(result.authors);
                let purchaseDate = new Date(result.purchaseDate);
                let productUrl = `https://www.amazon.co.jp/dp/${asin}`
                let productImageUrl = `https://images-na.ssl-images-amazon.com/images/P/${asin}.09.MZZZZZZZ.jpg`

                // Remove double quotes and CRLF from title
                title = title.replace(/"/g, '');
                title = title.replace(/\n|\r\n|\r/g, '');

                // Add record to batch
                let record = {
                    asin: asin,
                    title: title,
                    authors: authors,
                    purchaseDate: purchaseDate,
                    productUrl: productUrl,
                    productImageUrl: productImageUrl
                }
                batch.push({
                    action: 'addObject',
                    body: record
                })
            }
            let req = new Request(url, {
                method: 'POST',
                body: JSON.stringify({
                    requests: batch
                }),
                headers: headers
            })

            fetch(req)
                .then(response => {
                    if (response.status === 200) {
                        console.log(response.json());
                    } else {
                        throw new Error('Something went wrong on api server!' + response.json());
                    }
                })
                .then(response => {
                    console.debug(response);
                }).catch(error => {
                    console.error(error);
                });

        });
    });
};

sendKindleToAlgolia(appId, apiKey, indexName);
  • Algolia dashboard 画面に移動しデータがインデックスされていることを確認する。メニューから 'indices' をクリックし、indexName で指定したインデックスを選択。検索欄にクエリを入力すると検索結果が表示される

dashboard.png

その他

Aloglia Dashboardにログインするのがめんどくさい場合はWeb UIライブラリのInstantSearch.jsで比較的簡単にWebアプリにしてしまうこともできます -> 試しに作ってみました。ソースをコピペして AppId, APIキー、インデックス名を書き換えれば動くはずです。

参考:
Getting Started | Building Search UI | Guide | Algolia Documentation
Vue InstantSearchを使って検索機能を実現する | shinodogg.com
Vue InstantSearch (Algolia) を使った検索機能の実装 | by Kazuki Yonemoto | Medium

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
3
Help us understand the problem. What are the problem?