技术解读

以下内容由 GitRead 中文社区 编辑团队基于项目 README 与官方资料整理, 结合中文开发者的常见使用场景补充技术选型建议。具体以项目官方文档为准。

把 Open Library 的巨大 JSON 收窄成一张 ISBN 清单:LibrariesHacked/openlibrary-search 技术解剖

项目背景与痛点

Open Library 是 Internet Archive 旗下的开放书目项目,野心不小:给世上每一本书建一个页面。它对外近乎免费地开放了 openlibrary.org/search.json,代价则是返回体极其臃肿——一个常见关键词往往命中数百条记录,每条记录又挂着几十个字段、一串 edition key 和一坨 ISBN,JSON 体积轻松到 MB 级别。

可现实里没人在乎这堆元数据。编目员要的是能落地采购的 ISBN,二手书店的脚本要的是能拿去比价的标识符,阅读类 App 要的是补全一本书的确定 ID。也就是说,真正稀缺的不是"能不能搜到",而是把一段模糊的关键词翻译成一组确定性标识符——这一步没有官方接口,又脏又琐碎。

这个仓库干的就是这件脏活:做一层薄薄的投影,把宽口径的书目检索收窄成窄口径的 ISBN 输出。

核心技术揭秘

从定位推断,它的本质不是搜索引擎,而是一个检索结果投影器(projection layer)。数据流大致是三层:输入清洗 → 上游查询编排 → 结果规范化。

上游调用这一环,关键在于用 fields 参数做字段裁剪——只取 key、title、author_name、edition_count、isbn 等少数几个字段。这是 Open Library API 最容易被忽视的性能杠杆:默认返回的字段里,封面、主题标签、贡献者列表占了绝大部分体积,而下游一个都用不上。再叠加 limit 控制单页规模,响应体可以从 MB 级压到几十 KB。

请求走服务端而非浏览器直连,解决了两个隐性成本:一是 CORS 与 Internet Archive 对匿名 UA 的节流策略,二是让缓存成为可能——同一关键词的重复查询在图书馆场景里极其常见。

规范化才是真正难的地方。Open Library 的 isbn 字段是各 edition 的 ISBN 汇总,混着 ISBN-10 与 ISBN-13,有重复、有历史遗留的脏数据。要交付干净的列表,至少得做:剥离连字符、ISBN-10 与 ISBN-13 互转(补 978 前缀并重算校验位)、按 edition 维度去重、再按 edition_count 或相关度排序,把冷门重印本压到后面。

graph TD A[关键词输入] --> B[清洗与截断:去噪、限制长度] B --> C[构造上游请求:q + fields + limit] C --> D[Open Library Search API] D --> E{"HTTP 200 且 docs 非空?"} E -->|"否"| F[空结果或降级提示] E -->|"是"| G[字段投影:title / isbn / edition_count] G --> H[ISBN 归一化:10 位与 13 位互转] H --> I[跨 edition 去重与排序] I --> J[输出 ISBN 列表]

功能亮点与差异

杀手锏其实是"克制"。市面上更主流的选择是 Google Books API,但它需要 API Key、配额按项目计、对绝版书和公共领域作品覆盖偏弱。Open Library 的强项恰好是长尾:十九世纪的印本、非英语版本、早已绝版的冷门书,命中率明显更高。这个项目把"长尾覆盖"和"只给 ISBN"的简洁绑在了一起,接口窄到几乎不用文档。

第二点是可嵌入性。输出是纯标识符列表,天然适合被下游系统消费——不需要再写适配代码,塞进采购流程、编目工具或库存比对脚本都行。这种单一职责的设计,比做一个大而全的书目中台要务实得多。

应用场景与落地建议

适合的场景很明确:二手书商的批量比价与选品、图书馆编目辅助、阅读类产品的书籍信息补全、数字化项目的书目对齐。

生产环境里有几件事必须先做。其一,自建服务端代理加缓存,别让前端直连上游,否则用户 IP 暴露给第三方、限流一打就全站歇菜。其二,加上带退避的重试与并发上限,Internet Archive 不是商业 SLA 服务,突发流量下的 5xx 很常见。其三,结果必须二次校验:ISBN 校验位验一遍,标题与目标书目的相似度兜一遍,别把 Open Library 社区维护数据里的错漏直接灌进你的库存表。其四,明确它是检索入口而非权威书目源,最终数据仍应以出版社或国家书目为准。

综合评价

优点: 职责单一、接口极窄,解决的是真实存在且长期被忽视的长尾需求;字段裁剪和 ISBN 归一化这两步,替使用者省掉了最容易踩坑的工程细节;基于开放数据,无 Key、无配额门槛,试用成本近乎为零。

缺点: 天花板很低——本质是一层薄适配器,核心逻辑几百行就能写完,很难沉淀为平台。质量上限被上游完全锁死:Open Library 的书目由社区贡献,脏数据、错 ISBN、重复 edition 都在所难免。此外,项目维度上大概率缺少批量接口、限流治理和生产级测试,要真正投产,这一圈工程化得自己补。

一句话:它不是一个能撑起业务的系统,而是一块称手的垫片。放在正确的管线里,价值密度很高;指望它当书目中台,则会失望。

关于

Searching Open Library by keywords to return ISBNs

描述取自 GitHub 官方 API,中文内容由 GitRead 中文社区 编辑团队整理。

简要分析

热度分
331
价值分
161
活跃状态
活跃

语言占比

PLpgSQL
Python

README

Open Library database

Open Library is an large online library of bibliographic data. They publish full data dumps of data on authors, works, and editions.

This project provides instructions and scripts for downloading and importing this data into a PostgreSQL database, and some sample queries to test the database.

The database is primarily aimed at querying using ISBN and includes tables specifically for these identifiers. It could be extended to change this to other identifiers, such as Open Library ID, or text searching by title or author.

Getting started

The following steps should get you up and running with a working database.

  1. Install the required prerequisites so that you have a local database server.
  2. Download the data from Open Library.
  3. Run the processing the data scripts to prepare for import.
  4. Import the data into the database.

Prerequisites

  • Python 3 - Tested with 3.10
  • PostgreSQL - Version 15 is tested but all recent versions should work. The scripts should be run on a local server - if you need to transfer this to the cloud, it would be better done once the database has been created.
  • Disk space - The data files are large, and the uncompressed editions file is 45GB. You will need at least 250GB of free space to import all the data.

Downloading the data

Open Library offer bulk downloads on their website, available from the data dumps page.

These are updated every month. The downloads include (compressed sizes shown):

  • Editions (~10.5GB)
  • Works (~3.5GB)
  • Authors (~0.5GB)
  • All types (~10GB)

Download the Editions, Works, and Authors data dumps.

wget https://openlibrary.org/data/ol_dump_editions_latest.txt.gz -P ~/downloads
wget https://openlibrary.org/data/ol_dump_works_latest.txt.gz -P ~/downloads
wget https://openlibrary.org/data/ol_dump_authors_latest.txt.gz -P ~/downloads

Move the data from your downloads folder.

mv ~/downloads/ol_dump_authors_*txt.gz ./data/unprocessed/ol_dump_authors.txt.gz
mv ~/downloads/ol_dump_works_*txt.gz ./data/unprocessed/ol_dump_works.txt.gz
mv ~/downloads/ol_dump_editions_*txt.gz ./data/unprocessed/ol_dump_editions.txt.gz

Then uncompress the data files.

gzip -d -c data/unprocessed/ol_dump_editions.txt.gz > data/unprocessed/ol_dump_editions.txt
gzip -d -c data/unprocessed/ol_dump_works.txt.gz > data/unprocessed/ol_dump_works.txt
gzip -d -c data/unprocessed/ol_dump_authors.txt.gz > data/unprocessed/ol_dump_authors.txt

This should leave you with 3 unprocessed files in the data/unprocessed directory.

Processing the data

Unfortunately the downloads provided don’t play nicely for direct importing into PostgreSQL. They error on import as the number of columns provided varies. Cleaning it up can be difficult as the text file for editions is 25GB.

To do note: Check if this is still the case and if so there could be some Linux tools to fix this - maybe try sed and awk

Instead, the file openlibrary_data_process.py reads in the text file and writes it out again for each row, but only where there are 5 columns.

Because the files are huge and are only going to grow (editions is now 45gb+) the openlibrary_data_process.py file also splits the data into smaller files to load sequentially. You can change the number of lines in each chunk by using the LINES_PER_FILE setting in the script. The default is 2 million.

Once the files are split you can delete the 3 .txt files in the uncompressed folder because you will need around 250 Gb of freespace to load all 3 files into the database without encountering lack of space errors. If you have plenty of space you can keep the files!

python openlibrary_data_process.py

This generates multiple files into the data/processed directory. One of those files (filenames.txt) is used as a checklist when loading the data.

On a Macbook M3 this process took 15 minutes.

Import into database

We import the data directly into PostgreSQL tables and can then do complex searches with SQL.

There are a series of database scripts which will create the database and tables, and then import the data. These are in the database folder. The data files (created in the previous process) need to be within the data/processed folder for this to work.

The PostgreSQL database command line tool psql is used to run the scripts. The following command will create the database and tables and load the data. Replace username with your database server username.

psql --set=sslmode=require -f openlibrary-db.sql -h localhost -p 5432 -U username postgres

This process is intensive and you should expect it to take a long time. On a Macbook M3 this took about 5 hours.

Database details

The database is split into 5 main tables

Data Description
Authors Authors are the individuals who write the works
Works The works as created by the authors, with titles, and subtitles
Author Works A table linking the works with authors
Editions The particular editions of the works, including ISBNs
Edition ISBNs The ISBNs for the editions

Query the data

That’s the database set up - it can now be queried using SQL.

Get details for a single item using the ISBN13 9781551922461 (Harry Potter and the Prisoner of Azkaban):

select
    e.data->>'title' "EditionTitle",
    w.data->>'title' "WorkTitle",
	a.data->>'name' "Name",
    e.data->>'subtitle' "EditionSubtitle",
    w.data->>'subtitle' "WorkSubtitle",
    e.data->>'subjects' "Subjects",
    e.data->'description'->>'value' "EditionDescription",
    w.data->'description'->>'value' "WorkDescription",
    e.data->'notes'->>'value' "EditionNotes",
    w.data->'notes'->>'value' "WorkNotes"
from editions e
join edition_isbns ei
    on ei.edition_key = e.key
join works w
    on w.key = e.work_key
join author_works a_w
	on a_w.work_key = w.key
join authors a
	on a_w.author_key = a.key
where ei.isbn = '9781551922461'

评论

暂无评论