基于维基百科的在线-离线结合的数据策展和知识库构建方法

OOCDC 是一种基于维基百科数据的在线-离线结合的数据策展方法 (An Online-Offline Combined Data Curation Method Based on Wikipedia Data).

方法介绍

concept_dataset/
├── concept_data_info.json
├── data
├── extract_DEIE_data.py
├── index_cache.pkl
├── pipeline.py
├── postprocess.py
├── process_wikidump.py
├── search_wiki.py
└── utils.py

数据准备

首先下载维基百科官方发布的 dump 文件. 然后用 WikiExtractor 提取为 JSON 样式的文本, 这样就获得了离线的维基百科知识库 (详见附录). 文件保存到项目根目录下的 extract_wikipedia/zhwiki-20240820-pages-articles-json/AA/目录.

文本知识库的预处理

此时得到的 AA/ 目录下有 wiki00~wiki43 共 44 个文件. 这 44 个文件的每一行都是一个 JSON 字符串, 代表一个维基百科词条页面, 包含页面 id, 页面链接, 标题和文本内容等信息.

为了阅读和处理的方便, 还需进行以下步骤:

  1. 这些文件是 Unicode 编码, 不可直接阅读, 因此首先通过 process_wikidump.unicode2utf8()将其转换为 UTF-8 格式, 保存到 AA_readable/目录.
  2. 这些文件中有相当一部分是繁体中文, 可以通过 OpenCC 库转换为简体. 这里使用process_wikidump.batch_convert()方法. 转换后的文件保存在AA_zh-hans/目录下.
  3. 由于这 44 个文件大小不一 (每个文件中存储的词条页面数量即 JSON 行数差异很大), 不利于之后建立索引进行快速查找, 因此采用 process_wikidump.rebalance_file_size()方法来重新平衡各文件的权重. 例如每个文件保存 1000 个词条, 这样文件数量会从 44 个增加到 2701 个, 但相应得索引效率也将大大提升. 重平衡后的文件保存在AA_rebalanced/目录下.
  4. 通过process_wikidump.build_index_cache()方法建立知识库索引, 可以根据页面 id 直接定向到该页面文本所在的知识库存储文件.

文本知识库的预处理阶段主要通过 process_wikidump.py中的三个函数完成:

wikidump_dir = '../extract_wikipedia/zhwiki-20240820-pages-articles-json/'
raw_file_dir = os.path.join(wikidump_dir, 'AA')
readable_file_dir = os.path.join(wikidump_dir, 'AA_readable')
converted_file_dir = os.path.join(wikidump_dir, 'AA_zh-hans')
rebalanced_file_dir = os.path.join(wikidump_dir, 'AA_rebalanced')

unicode2utf8(raw_file_dir, readable_file_dir)

batch_convert(readable_file_dir, converted_file_dir, conversion='t2s')

rebalance_file_size(converted_file_dir, rebalanced_file_dir, lines_per_file=1000, filename_index_length=4)

经过处理后的extract_wikipedia/zhwiki-20240820-pages-articles-json/AA/目录如下:

.
└── extract_wikipedia
    └── zhwiki-20240820-pages-articles-json
        ├── AA
        ├── AA_readable
        ├── AA_rebalanced
        └── AA_zh-hans

搜索目标页面

search_wiki.py中定义了WikiSearcher类, 该类实现了基于 MediaWiki API 搜索指定类别或关键词的维基百科页面的方法. 其中,

  • api_search_sr()基于 API: Search(sr) 来搜索与目标查询词相关的页面.
  • api_search_cm()基于 API: Categorymembers(cm) 来搜索某个类别下的所有页面.

此外还有以下辅助功能:

  • aggregate_search_result()方法聚合搜索结果(文章页面)并进行去重.
  • search_categories_start_from_ckpt()针对 cm 搜索量高, 耗时长, 存在终端风险的问题, 设计了 checkpoint 保存和继续搜索的功能.
  • manual_edit_category_queue_ckpt()用来人工编辑检查点. 适合在队列中出现大量无用信息的情况. 手工将队列中不需要搜索的类别删除, 以节约搜索时间.

需要注意的是, 本步骤得到的搜索结果只是页面的 id 以及关键词所在的片段(snippet), 而不是完整的文本页面. 因此后续步骤需要根据搜索到的页面 id 来获取真正的完整页面文本内容.

ws = WikiSearcher(endpoint=f'https://zh.wikipedia.org/w/api.php')

query = '"疫情"'
ws.api_search_sr(query=query)

categories = ['礦業']
ws.search_categories(categories)

ws.manual_edit_category_queue_ckpt('./data/api_search/bfs_search_20240830-120342', 'ckpt_category_queue_1701_interrupt.pkl')
ws.search_categories_start_from_ckpt('./data/api_search/bfs_search_20240830-120342', 'ckpt_category_visited_10250_interrupt.pkl', 'edited_ckpt_category_queue_1701_interrupt.pkl')

bfs_search_result = './data/api_search/bfs_search_20240830-120342'
ws.aggregate_search_result(bfs_search_result)

数据分发和后处理

pipeline.py中, 实现了根据爬取到的页面 id 获取知识库中完整页面内容, 并将其保存为数据集的过程.

  • postprocess.deliver_page_obj()依据页面id, 将知识库中的页面对象转存到对应的类别数据集文件中.

在获得初步的数据集后, 对其中的每个样本(每个页面的文本内容)进行后处理.

  • postprocess.data_clear()实现了数据清洗
  • postprocess.data_truncate()对每个页面文本根据关键词(可指定)提取出两个小片段(指定文本长度范围), 来避免原始页面文本过长的问题.
s_time = time.time()

gen_emptyset()

# 分发维基百科数据
wiki_KB_dir = '../extract_wikipedia/zhwiki-20240820-pages-articles-json/AA_rebalanced/'
search_res_dir = './data/api_search/'
concept_data_info_file = 'concept_data_info.json'

with open(concept_data_info_file, 'r', encoding='utf-8') as f:
	concept_data_info = json.load(f)
print(f'> Delivering wikipedia data examples according to {
     concept_data_info_file}...\n')

# 建立索引
file_list, _ = get_file_list(wiki_KB_dir)
print(f'> All files in {
     wiki_KB_dir}:\n{
     file_list}\n')
start_page_ids = get_start_page_ids(wiki_KB_dir, file_list)
print(f'> First page\'s id in each file: \n{
     start_page_ids}\n')
if os.path.exists('index_cache.pkl'):
	user_input_2 = input('Page index cache already exists. Generate it again? [y/n] ')
	if user_input_2 in ['y', 'Y']:
		build_index_cache(wiki_KB_dir, file_list)
else:
	build_index_cache(wiki_KB_dir, file_list)

# 依次处理每个类型的数据
for concept_type in concept_data_info.keys():  # 1~20
	
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值