本ブログでは、全記事のメタデータを HTML ビルド時に解析し、Cypher クエリに変換した上で Neo4j Aura に保存しています。
今回、記事本文に含まれる外部サイトへのリンク数も解析対象に付与しました。 データモデリングの一例としてご紹介します。
ブログの記事には、Wikipedia やドキュメントへの外部リンクを追加することがよく有ります。
外部リンクの問題は、時々リンク先がリンク切れを起こしており、読者の方がクリックしても本来意図した情報にたどり着くことができない点です。
そこで、ブログ記事に含まれる外部リンクをまずは分析できるようにする必要が有りました。もちろん、「どの記事からリンクされているのか」という関係性もモデルに含む必要 がありました。
また、ブログの価値を向上するために、どの外部リンクへのリンクをよく貼っているのか、どういった記事からどの種類のサイトへのリンクを貼ることが多いのか、分析していく必要が有りました。
以前 "Blog Relevant Tags Internal" の記事でもご紹介したとおり、本ブログは Gatsby を利用して、事前に静的 HTML をビルドしています。今回も、そのビルドプロセスで全記事のメタデータを解析し、Cypher クエリに変換し、Neo4j Aura に Write する形を取りました。
本ブログは、Gatsby のプラグインである gatsby-transformer-remark
を利用しています。記事は Markdown ファイルで書いていますが、ビルド時にこのプラグインが remark.js を用いて Abstract Syntax Tree (AST) に変換し、最終的には HTML へと変換して出力しています。
remark.js では、unified.js が策定している一連の API に沿った形で AST を定義しています。allMarkdownRemark
が返却するフィールドの中にある html
がそれに該当します。
{
postsRemark: allMarkdownRemark(
limit: 100
) {
edges {
node {
id
html
}
}
}
返却結果のイメージとしては、以下のような AST が JSON で返却されます。
"html": {
"type": "root",
"children": [
{
"type": "element",
"tagName": "h3",
"properties": {},
"children": [
{
"type": "text",
"value": "About This Blog"
}
]
},
{
"type": "text",
"value": "Hello, world!\n"
},
ここまで手に入ったら、後は AST を歩いて適切な Cypher クエリに変換するコードを書くだけです。
データモデリングとしてはシンプルです。記事を表す (:Post)
ノードが、それぞれリンクを示す (:URL)
ノードに対して、-[:INCLUDES_LINK_TO]
リレーションを含みます。
MERGE (p:Post { slug: '...', title: '...' })
MERGE (u:URL { hostname: $hostname, pathname: $pathname, protocol: $protocol, href: url.href})
MERGE (p)-[:INCLUDES_LINK_TO]->(u)`
また、Hostname ごとの分析を容易にしたかったので、(:Hostname)
ノードも作成しました。(:URL)
ノードに対して、-[:IS_HOSTED_AT]->
リレーションを作成しています。
MERGE (h:Hostname { value: $hostname })
MERGE (h)<-[:IS_HOSTED_AT]-(u)`
執筆時点における (:Post)
, (:URL)
, (:Hostname)
の全体像は以下のようになっています。
以下の Cypher クエリでは、被リンクが 3 つ以上の外部サイトの Hostname を、被リンク数とともにテーブルで表示させます。
MATCH p=(h:Hostname)<-[:IS_HOSTED_AT]-(:URL)<-[:INCLUDES_LINK_TO]-(:Post)
WITH h, count(p) as score
WHERE score >= 3
RETURN h.value as hostname, score
ORDER BY score DESC
例えば、執筆時点では以下のような結果になっています。
hostname | score |
---|---|
neo4j.com | 17 |
en.wikipedia.org | 4 |
www.linkedin.com | 3 |
以下の Cypher クエリでは、被リンク数が 3 つ以上の外部サイトの URL を表示させます。Hostname に正規化させない結果を表示させたい場合は以下を使います。
MATCH p=(u:URL)<-[:INCLUDES_LINK_TO]-(:Post)
WITH u, count(p) as score
WHERE score >= 3
RETURN u.href, score
以上、本サイトに導入した記事と外部 URL との関連性を分析するためのデータモデリングと、実際の仕様例を幾つか紹介しました。