日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > python >内容正文

python

python 知识图谱demo_古诗词知识图谱Demo

發(fā)布時(shí)間:2024/1/1 python 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python 知识图谱demo_古诗词知识图谱Demo 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

早前調(diào)研了知識(shí)圖譜的基礎(chǔ)概念和技術(shù)框架,最近這兩個(gè)月倒騰了一個(gè)古詩(shī)詞的圖譜demo,僅以此文記錄一下實(shí)驗(yàn)過(guò)程。從零開(kāi)始做這個(gè)Demo,整個(gè)過(guò)程大致分為三大步驟:數(shù)據(jù)采集,數(shù)據(jù)存儲(chǔ)以及圖譜應(yīng)用,全文將按這三步進(jìn)行記錄。

一、數(shù)據(jù)采集

既然是從零開(kāi)始,那第一步就是要爬取數(shù)據(jù)。搜了幾個(gè)詩(shī)詞網(wǎng)站,對(duì)比網(wǎng)頁(yè)排版結(jié)構(gòu)和內(nèi)容豐富程度,個(gè)人覺(jué)得古詩(shī)詞網(wǎng)是個(gè)不錯(cuò)的選擇,在這里感謝站長(zhǎng)為經(jīng)典文化傳承作出的貢獻(xiàn)。

1. 網(wǎng)頁(yè)分析

F12打開(kāi)詩(shī)詞列表頁(yè)的源碼,查看頭部信息如下圖:

請(qǐng)求的url格式固定,只有頁(yè)碼改變;請(qǐng)求的類型為get。

多看幾個(gè)頁(yè)面,可以發(fā)現(xiàn)請(qǐng)求頭中Cookie的hm_lvt和hm_lpvt為兩個(gè)時(shí)間戳,不同頁(yè)面只有hml_pvt發(fā)生改變;old_url取值為當(dāng)前頁(yè)碼;Referer也是隨頁(yè)碼改變的固定格式url。

請(qǐng)求列表頁(yè)面的返回結(jié)果為json列表,可以非常方便地提取需要的信息,而不用去html中定位并解析目標(biāo)元素,省去了爬蟲中的一半工作量:

每一個(gè)json對(duì)應(yīng)一首詩(shī)詞,包含標(biāo)題、正文、作者、朝代、標(biāo)簽、體裁、作者介紹、譯注、賞析等信息,這種結(jié)構(gòu)化的數(shù)據(jù),也免去了數(shù)據(jù)抽取和整理的很多工作。

2. 爬蟲代碼

這一類網(wǎng)站廣告很少,也沒(méi)有收費(fèi)業(yè)務(wù),帶有公益性質(zhì),網(wǎng)站服務(wù)器一般也扛不住爬蟲的壓力,常常會(huì)采取一些反爬措施,比如封禁IP。為了爬取這些網(wǎng)站,一方面要降低爬取速度;另一方面要維護(hù)代理池,在被封的時(shí)候更換IP。爬取過(guò)程中及時(shí)保存爬蟲結(jié)果,并記錄爬取失敗的頁(yè)面,方便以后再重爬。

def crawl_pages(page_list, save_path, ip_pool, retry_times=5):

fail_list = list()

lvt_code = int(time.time())

ip = random.choice(ip_pool)

for page in page_list:

time.sleep(3 * random.random())

lpvt_code = int(time.time())

page_url = 'https://www.gushici.com/poetry_list?page={0}'.format(page)

referer = 'https://www.gushici.com/p_{0}'.format(page)

headers = {'Host': 'www.gushici.com',

'Connection': 'keep-alive',

'Accept': '*/*',

'X-Requested-With': 'XMLHttpRequest',

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',

'Referer': referer,

'Accept-Encoding': 'gzip, deflate, br',

'Accept-Language': 'zh-CN,zh;q=0.9',

'Cookie': 'JSESSIONID=48304F9E8D55A9F2F8ACC14B7EC5A02D; Hm_lvt_98209c07e81fcbdd5f79bd9e94c617eb={0}; Hm_lpvt_98209c07e81fcbdd5f79bd9e94c617eb={1};\old_url=/p_{2}'.format(lvt_code, lpvt_code, page)}

times = 0

flag = False

while times <= retry_times:

times += 1

try:

response = requests.get(page_url, headers=headers, proxies={'https': ip}, verify=False, timeout=10)

flag = True

with open(os.path.join(save_path, page), 'w', encoding='utf-8') as f:

json.dump(response.text, f, ensure_ascii=False)

break

except:

ip = random.choice(ip_pool)

if not flag:

fail_list.append(page)

with open(os.path.join(save_path, 'fail'), 'w', encoding='utf-8') as f:

json.dump(fail_list, f, ensure_ascii=False)

二、數(shù)據(jù)存儲(chǔ)

知識(shí)圖譜的數(shù)據(jù)層有多重存儲(chǔ)方式,本文選擇采用Neo4j搭建。Noe4j是一個(gè)高性能的輕量級(jí)圖形數(shù)據(jù)庫(kù),應(yīng)對(duì)小型知識(shí)圖譜綽綽有余。雖然關(guān)系型數(shù)據(jù)庫(kù)通過(guò)多重join也可以實(shí)現(xiàn)數(shù)據(jù)間的復(fù)雜關(guān)系查詢,但是多表數(shù)據(jù)join然后過(guò)濾篩選導(dǎo)致性能會(huì)非常差,而圖數(shù)據(jù)庫(kù)很好地解決這樣的問(wèn)題,它只用遍歷相關(guān)節(jié)點(diǎn),不用操作全量數(shù)據(jù),性能會(huì)大大提升。

1. Neo4j安裝

從Neo4j官網(wǎng)可以下載開(kāi)源的Noe4j社區(qū)版,解壓到D盤,然后配置環(huán)境變量。注意:Neo4j依賴于Java運(yùn)行環(huán)境,安裝Neo4j前請(qǐng)檢查本機(jī)是否安裝Java并配置Java的環(huán)境變量。

打開(kāi)cmd命令行窗口,進(jìn)入安裝目錄下的bin文件夾,執(zhí)行“neo4j install-service”命令,安裝Neo4j服務(wù)。然后執(zhí)行“neo4j start”命令,啟動(dòng)Neo4j的服務(wù)。

2. Neo4j操作

Neo4j是一種圖數(shù)據(jù)庫(kù),其中并沒(méi)有數(shù)據(jù)表的概念,只包含節(jié)點(diǎn)和邊,節(jié)點(diǎn)表示實(shí)體,邊表示實(shí)體間的關(guān)系(分為有向關(guān)系和無(wú)向關(guān)系),節(jié)點(diǎn)和邊可以包含鍵值對(duì)表示的屬性。

用慣了關(guān)系型數(shù)據(jù)庫(kù),初次接觸圖數(shù)據(jù)庫(kù)感覺(jué)有點(diǎn)別扭。為了便于自己理解,我是這樣來(lái)類比的:

節(jié)點(diǎn)和關(guān)系是圖數(shù)據(jù)庫(kù)中定義的最原始的兩個(gè)基類,節(jié)點(diǎn)(關(guān)系)的標(biāo)簽表示由節(jié)點(diǎn)(關(guān)系)基類派生出來(lái)的一類節(jié)點(diǎn)(關(guān)系)。當(dāng)導(dǎo)入數(shù)據(jù)之后,具有屬性值的某一個(gè)節(jié)點(diǎn)(關(guān)系),就是該標(biāo)簽對(duì)應(yīng)的節(jié)點(diǎn)(關(guān)系)派生類所生成的實(shí)例。

(1)導(dǎo)入數(shù)據(jù)

Neo4j提供import命令,可以批量導(dǎo)入csv格式的數(shù)據(jù)。針對(duì)json格式的數(shù)據(jù),可以轉(zhuǎn)為csv格式,然后用import導(dǎo)入,注意json中的雙引號(hào)需要進(jìn)行轉(zhuǎn)義。為避免格式轉(zhuǎn)換過(guò)程中的錯(cuò)誤,可以調(diào)用apoc函數(shù)庫(kù)中的json導(dǎo)入工具。

apoc的安裝方式為:從github中下載apoc的jar包,將jar包復(fù)制到Neo4j安裝目錄的plugins路徑下,在neo4j.conf中配置apoc.import.file.enabled=true,表示允許apoc導(dǎo)入文件。重啟Neo4j服務(wù),調(diào)用apoc.load.json即可導(dǎo)入json數(shù)據(jù)。

(2)查詢數(shù)據(jù)

Neo4j的查詢語(yǔ)言為Cypher(第一眼看成了Cython,然而這兩個(gè)半點(diǎn)不沾邊)。官網(wǎng)有完整版的Cypher手冊(cè),本文只挑選最基礎(chǔ)的幾個(gè)語(yǔ)句簡(jiǎn)要介紹。

A.增:

新建節(jié)點(diǎn): CREATE (node: NodeType {AttributeKey : AttributeValue})

// 創(chuàng)建一個(gè)姓名為Jack的Person類的節(jié)點(diǎn),并返回該節(jié)點(diǎn)

CREATE (a:Person {name:"Jack"})

RETURN a

新建關(guān)系:不能單獨(dú)創(chuàng)建關(guān)系,必須指明關(guān)系的起始節(jié)點(diǎn)和終止節(jié)點(diǎn)。--表示無(wú)向關(guān)系,->和 EndNode

// 創(chuàng)建兩個(gè)Person之間Knows的關(guān)系,并返回節(jié)點(diǎn)和關(guān)系

CREATE (a:Person)-[k:KNOWS]-(b:Person)

RETURN a, k, b

B.查:

查詢節(jié)點(diǎn):MATCH (node: NodeType {AttributeKey : AttributeValue}) WHERE node.AttributeKey = AttributeValue

// 查詢1970年后出生的Person節(jié)點(diǎn),并返回節(jié)點(diǎn)

MATCH (n)

WHERE n.born > 1970

RETURN n;

查詢關(guān)系:MATCH StartNode - (relationship: RelationshipType {AttributeKey : AttributeValue}) -> EndNode WHERE relationship.AttributeKey = AttributeValue

// 查詢自從2015年起居住(LIVES_IN)在NewYork城市(City)的名叫Mike的人(Person),并返回節(jié)點(diǎn)和關(guān)系

MATCH (p:Person {name:"Michel"})-[s:LIVES_IN]->(c:City {name:"NewYork"})

WHERE s.since = 2015

RETURN p,s,c

C.改:

修改屬性:MATCH (variable : NodeType|RelationshipType) SET variable = {AttributeKey : AttributeValue}

// 查詢名為Jack的Person類節(jié)點(diǎn),并將名字改為Michel,年齡改為23

MATCH (p:Person)

WHERE p.name = "Jack"

SET p = {name: "Michel", age: 23}

D.刪:

刪除節(jié)點(diǎn):與該節(jié)點(diǎn)相關(guān)的關(guān)系也需要?jiǎng)h除。MATCH (node) - [relationship] - () DELETE node, relationship

// 刪除名為Jack的Person節(jié)點(diǎn)及關(guān)聯(lián)關(guān)系

MATCH (p:Person)-[relationship]-()

WHERE p.name = "Jack"

DELETE relationship, p

刪除屬性:MATCH (node) - [relationship] - () REMOVE node.AttributeKey, relationship.AttributeKey

// 刪除名為Michel的Person節(jié)點(diǎn)的年齡屬性

MATCH (p:Person)

WHERE p.name = "Michel"

REMOVE p.age

3. Neo4j實(shí)踐

本文設(shè)計(jì)的知識(shí)圖譜包含三類節(jié)點(diǎn):詩(shī)詞(Poem)、作者(Author)、標(biāo)簽(Tag)。作者與詩(shī)詞是寫作(WRITE)的關(guān)系,詩(shī)詞、作者與標(biāo)簽是標(biāo)識(shí)(LABEL)關(guān)系。

// 在三類節(jié)點(diǎn)上創(chuàng)建索引

create index on :Poem(uuid);

create index on :Author(name);

create index on :Tag(tag);

// 將數(shù)據(jù)導(dǎo)入Neo4j

call apoc.periodic.iterate('call apoc.load.json("web_file_poetry.json") yield value as poem',

'merge (p:Poem{uuid: poem.poem_id})

set p.title = poem.title, p.content=poem.poem, p.tag=poem.tag, p.appreciation=poem.appreciation, p.background=poem.background

// 作者節(jié)點(diǎn)

merge (a:Author{name: poem.poet, dynasty: poem.dynasty})

// 作者到詩(shī)詞的關(guān)系

merge (a)-[r1:WRITE]->(p)',

{batchSize:100000, iterateList:true, parallel:true});

// 建立詩(shī)詞、作者與標(biāo)簽之間的關(guān)系

match (a:Author)-[:WRITE]->(p:Poem)

where p.tag <> ''

unwind split(trim(p.tag), ",") as tag

// 標(biāo)簽節(jié)點(diǎn)

merge (t:Tag{tag: tag})

// 詩(shī)詞到標(biāo)簽的關(guān)系

merge (p)-[r1:LABEL]->(t)

// 作者到標(biāo)簽的關(guān)系

merge (a)-[r2:LABEL]->(t);

圖數(shù)據(jù)庫(kù)創(chuàng)建成功之后,可以查詢看看效果,Neo4j的可視化做的還是挺好看的。

三、圖譜應(yīng)用

知識(shí)問(wèn)答是基于知識(shí)圖譜的一項(xiàng)應(yīng)用,前沿的問(wèn)答系統(tǒng)多采用深度學(xué)習(xí)、自然語(yǔ)言處理等技術(shù)。本文采用最簡(jiǎn)單的正則匹配( ̄▽ ̄)~*

1.首先,定義可以回答的問(wèn)題類型:

查找詩(shī)詞的正則:

source_list = [

'[\"\'“‘《]?(?:是|出自|來(lái)[自|源])(?:哪[首|篇|個(gè)|里|兒|]?|什么)的?(?:[詩(shī)詞][文句]?|文章|句子)?',

'[\"\'“‘《]?的(?:來(lái)源|出處|(?:整[首|篇]|完整|全)[詩(shī)詞文])',

'(?:含有?|包[含括])[\"\'“‘《]?的(?:[詩(shī)詞][文句]?|文章|句子)'

]

source_list = list(map(re.compile, source_list))

查找作者的正則:

author_list = [

'[\"\'“‘《]?的(?:作者|[詩(shī)詞]人)',

'[\"\'“‘《]?是(?:誰(shuí)|哪[位個(gè)])(?:作者|[詩(shī)詞]人)?',

]

author_list = list(map(re.compile, author_list))

查找標(biāo)簽的正則:

tag_list = [

'(?:寫|描[寫繪述]|表達(dá))(\S+?)的?[詩(shī)詞]',

]

tag_list = list(map(re.compile, tag_list))

整合問(wèn)題正則:

rules = {

'source': source_list,

'author': author_list,

'tag': tag_list,

}

2.其次,根據(jù)正則判斷問(wèn)題類型,并提取問(wèn)題中的要素

def match(question):

match_result = None

for mode, temp_list in rules.items():

for temp in temp_list:

text = temp.findall(question)

if text:

match_result = (mode, text[0])

break

return match_result

3.最后,從Neo4j中根據(jù)問(wèn)題要素查找并返回問(wèn)題答案

def parse(question):

match_result = match(question)

if match_result is None:

return None

mode, text = match_result

res = None

cql = None

if mode == 'source':

cql = 'match (p:Poem) where p.content contains "{0}" return p.title, p.content'.format(text)

elif mode == 'author':

cql = 'match (a:Author)-[:WRITE]->(p:Poem) where p.content contains "{0}" return a.name'.format(text)

elif mode == 'tag':

tag_list = jieba.lcut(text)

cql = 'match (p:Poem)-[:LABEL]->(t:Tag) where t.tag in {0} return p.content, t.tag'.format(tag_list)

else:

pass

if cql:

res = neo4j_graph.run(cql).to_data_frame()

return res

后記:

本文只是搭建了一個(gè)非常小的圖譜demo,后續(xù)還有很多地方需要完善,如有遺漏或錯(cuò)誤,請(qǐng)大家不吝指出,歡迎交流。

總結(jié)

以上是生活随笔為你收集整理的python 知识图谱demo_古诗词知识图谱Demo的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。