SPARQL-proxy

提供:TogoWiki

移動: 案内, 検索

SPARQL-proxy は、クライアントと SPARQL エンドポイントの間で動作するミドルウェアで、 山中さんが SPARQLthon で作成されたオリジナルを改訂したものです。

目次

主な機能

  • SPARQL クエリをパースし、更新系のクエリを実行できないようにする
  • SPARQL クエリをジョブスケジューリングしてからトリプルストアに投げる(負荷集中の低減)
  • ジョブのタイムアウトを指定できる
  • 同時に実行するジョブの数を指定できる
  • 管理画面からジョブを確認したり削除したりできる
  • SPARQL 検索結果をキャッシュして2度目からトリプルストアを使わずに結果を返す(レスポンスの向上)
  • キャッシュは memory, file, redis, memcached を選択して利用できる
  • キャッシュを圧縮してサイズを抑えることができる
  • クエリのログを取得できる

実験的な機能

  • 大量な結果が返る SPARQL クエリを LIMIT/OFFSET を自動的につけて分割実行する

最近の追加機能

  • Virtuoso 独自の拡張「DEFINE sql:select-option "order"」などを許容するように変更
    • ただし、SELECT などで sql:hogehoge とか option() などを使っている場合には対応していない
  • 180323 ver.
    • [ ] を使ったクエリは SPARQL パーザーが _:b0 形式のブランクに書き換えるが、ブランクにクエリを超えて連番つけるので、これまでは [ ] を使うクエリでキャッシュが効かなかった。パーザーを毎回リセットすることで、キャッシュが効くようになりました

レポジトリ

インストール

node.js の安定版をインストール(展開して bin/node, bin/npm を ~/local/bin などにリンクする)

$ wget --no-check-certificate https://nodejs.org/dist/v6.10.0/node-v6.10.0-linux-x64.tar.xz

sparql-proxy の現状版をダウンロードしてインストール

$ git clone https://github.com/dbcls/sparql-proxy.git
$ cd sparql-proxy
$ npm install

一部の依存ライブラリが GCC 4.8 以降の新しいものを必要とするので注意。

起動

$ cat startup.sh
#!/bin/sh

PREFIX=/opt/proxy

export PATH="$PREFIX/bin:$PREFIX/local/bin:$PATH"

# REDIS_URL=localhost:6379 \
# MEMCACHE_SERVERS=localhost:11211,localhost:11212 \
# JOB_TIMEOUT=300000 \
# DURATION_TO_KEEP_OLD_JOBS=60000 \
# COMPRESSOR=snappy \

(
cd $PREFIX/git/sparql-proxy

QUERY_LOG_PATH=$PREFIX/log/proxy.log \
CACHE_STORE=file \
CACHE_STORE_PATH=$PREFIX/cache \
MAX_CONCURRENCY=3 \
TRUST_PROXY=true \
PORT=3000 \
SPARQL_BACKEND=http://dev.togogenome.org/sparql \
ADMIN_USER=admin \
ADMIN_PASSWORD=hogehoge \
$PREFIX/bin/npm start 2>&1 >> $PREFIX/log/server.log &
)

これで http://localhost:3000/ を開くと SPARQL を実行する画面が表示される。

foreverでdaemon化

$ npm install -g forever
$ PORT=3000 SPARQL_BACKEND=http://aaa.bbb.ccc/sparql forever start -c "npm start" /path_to_sparql-proxy_dir
$ forever list     # forever 稼働中リスト
$ forever stop NNN   # list で確認したuidを用いて停止

/opt/proxy/git/sparql-proxy にインストールし、npmやforeverが/opt/proxy/local/binにある場合

% cat startup.sh
#!/bin/sh

PREFIX=/opt/proxy

(
cd $PREFIX/git/sparql-proxy

QUERY_LOG_PATH=$PREFIX/log/proxy.log \
CACHE_STORE=file \
CACHE_STORE_PATH=$PREFIX/cache \
MAX_CONCURRENCY=3 \
TRUST_PROXY=true \
PORT=14990 \
SPARQL_BACKEND=http://example.org/sparql-backend \
ADMIN_USER=admin \
ADMIN_PASSWORD=togo \
$PREFIX/local/bin/forever --workingDir $PREFIX/git/sparql-proxy $PREFIX/local/bin/npm start
)
  • Defaultでは 10,000 binidngs まで
    • 環境変数 MAX_LIMIT で設定

デプロイ

これまでどおりの URL たとえば http://example.org/sparql を sparql-proxy を使ったものに差し替えたい場合、 sparql-proxy を localhost:3000 などで起動しておいて、

server {
    listen       80;
    server_name  example.org

    location /sparql {
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Headers X-Requested-With;
        proxy_pass http://localhost:3000/sparql;
        proxy_redirect default;
    }
}

のようにすれば OK。

もし sparql-proxy のトップページや /admin を localhost:3000 ではなく外からもアクセスできるように、 同じドメイン 80 番ポートのサブパス、たとえば /proxy で公開する形でホストしたい場合は、 http://example.org/proxy/ でトップページを、http://example.org/proxy/sparql でエンドポイントを、 http://example.org/proxy/admin/ で管理画面を表示することになるが、 管理画面の更新が WebSockets で行われていることと、管理者ログインのクッキーへの対応ため、 下記のような書き換えが必要。

    location ~ ^/proxy/(.*)$ {
      proxy_pass http://localhost:3000/$1$is_args$args;
      proxy_redirect / /proxy/;
      proxy_cookie_path / /proxy/;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
    }

以上、いずれも Nginx の場合の設定例。

タイムアウト設定(nginxデフォルトは60秒)

proxy_read_timeout 3m;

SPARQLパース関連

  • Sparqlパース機能はもっと単純にならないか?
  • proxy 経由したときだけ遅くなるクエリがある
    • かなり重いクエリが下記のエラー
      • (node:15438) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 10): TypeError: Cannot read property 'map' of undefined
    • virtuoso で空白ノードをアンダーバーコロン形式 (例 '_:blank')や変数に入れた後で、OPTIONAL join を行うと遅くなる場合がある。[ ] 形式だと問題ない
      • _:b1, _:b2, _:b3 と数が多いほど遅くなる
    • SPARQL-proxy の SPARQL パーザーは [ ] 形式を '_:b' 形式に書き換えて実効するので、結果、遅くなる
  // virtuoso で問題ない

  ?s hoge:p [ a ?type ;
              rdf:value ? value ] .
  OPTIONAL { ?s hoge:p2 ? o .}

  ===========パーザーが書き換え============

  // virtuoso で遅い

  ?s hoge:p _:b1 .
  _:b1 rdf:type ?type .
  _:b1 rdf:value ?value .
  OPTIONAL { ?s hoge:p2 ? o .}
  • 解決法:可能なら、OPTIONAL join を先にする
DEFINE sql:select-option "order"

  OPTIONAL { ?s hoge:p2 ? o .}
  ?s hoge:p [ a ?type ;
              rdf:value ? value ] .
  • 空白ノード、プロパティ・パス関連でパースエラー
    • 主語を省略しつつ、空白ノード省略でプロパティ・パス (/,*,+ など) を使うとエラー
    • 主語か空白ノードの省略をやめると通る
  s  p  o ;
     p  [  p/p  o  ] .
  • サブクエリに FROM 行を入れるとパースエラー
  • 結果が変わる(場合がある?)
    • virtuoso直proxy経由
    • いろんなフィルタパターンでクエリを自動生成してるので、綺麗ではない入れ子になったクエリだけど、結果の一個目が出なく成ってた
      • キャッシュ消したら同じになった
個人用ツール