RDFをSPARQLを使ってRailsでDBっぽく扱ってみた
RDFをSPARQLで操作するハッカソンがあり、Activerecordを使ってのDB操作と同じようにRDFを扱いたかったのでactiverecordのメソッドっぽくラップしてみた。
まず以下をGemfileに追記する。
# Gemfile ... gem 'active_attr' gem 'sparql'
active_attr はテーブルを持たないモデルを少ない記述で作成できるようになるgem。
README読めば大体わかる。
次にモデルを記述していく。
具体例として尾道市の飲食店のモデルを示す。
class Restaurant require "sparql/client" include ActiveAttr::TypecastedAttributes include ActiveAttr::BlockInitialization attribute :name, type: String attribute :address, type: String attribute :lat, type: Float attribute :lng, type: Float attribute :image, type: String def self.all restaurants = [] results = self.all_query results.each do |result| restaurant = Restaurant.new do |r| r.name = result[:name] r.address = result[:address_name] r.lat = result[:lat].to_s.gsub('+', '') r.lng = result[:lng].to_s.gsub('+', '') r.image = result[:img] end restaurants << restaurant end restaurants end private def self.all_query client = SPARQL::Client.new("https://sparql.odp.jig.jp/api/v1/sparql") results = client.query(' select ?id ?address_name ?img ?name ?lat ?lng { ?s <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://purl.org/jrrk#CivicPOI>; <http://purl.org/jrrk#address> ?address. filter(regex(?address, "広島県尾道市")) ?s <http://odp.jig.jp/odp/1.0#genre> <http://odp.jig.jp/res/category/%E9%A3%9F%E3%81%B9%E3%82%8B>. ?s <http://purl.org/dc/terms/identifier> ?id. ?s ?p ?id. ?s <http://imi.ipa.go.jp/ns/core/rdf#住所> ?addresses. ?addresses <http://imi.ipa.go.jp/ns/core/rdf#表記> ?address_name. ?s <http://schema.org/image> ?img. ?s <http://www.w3.org/2000/01/rdf-schema#label> ?name. ?s <http://imi.ipa.go.jp/ns/core/rdf#地理座標> ?locate. ?locate <http://imi.ipa.go.jp/ns/core/rdf#緯度> ?lat. ?locate <http://imi.ipa.go.jp/ns/core/rdf#経度> ?lng. filter(lang(?name) = "ja") } ') results end end
実装の流れとしては
- 尾道市の飲食店データを得るためのクエリをSPARQLで書く。(ここがメイン)
- クエリから結果を返す
self.all_query
を書く。 self.all_query
の返り値をマッピングしてモデルのレコードインスタンスを生成するself.all
を書く。
これでRestaurant.all
を実行すれば尾道市の飲食店が全件取得できるようになる。
SPARQL難しい。