astamuse Lab

astamuse Labとは、アスタミューゼのエンジニアとデザイナーのブログです。アスタミューゼの事業・サービスを支えている知識と舞台裏の今を発信しています。

デザイナーもデブサミに行った方がいい理由をざっくりまとめてみた

f:id:astamuse:20180228115428j:plain

こんにちは、@YojiShirakiです。デザイナーです。

先日、デブサミ2018がありましたね。当日のタイムラインでは各セッションに関してのツイートが流れ、はてブでは資料情報などがホットエントリーに入っており、今年も盛況だったことが窺えます。私はというと、突如の高熱(インフル)で全く起きれずスマホでタイムライン追って様子を見ていました。

私はデザイナーですがデブサミなどエンジニア向けの大型のイベントは極力参加するようにしていて、毎回かなりよい感触を得ています。そして毎回「これはデザイナーも来た方がいいのでは?」と思っています。

そこで今回は、デザイナーである私が過去数年に渡ってデブサミに参加した経験から、デザイナーがデブサミに行った方がいい理由をまとめました。ぜひご覧ください。

デブサミはエンジニアのためだけのイベントではない

まず大前提ですがデブサミ(Developers Summit)はもはやエンジニアだけのイベントではありません。名前だけみるとエンジニアのためのイベントに見えますが、決してそんなことはありません。試しに先日のデブサミ2018のセッションをご覧ください。

ざっと見ただけでもエンジニア以外にも通じるセッションがいくつもあります。

どれもプロジェクトマネージャーやプロダクトマネージャーにとっても聞く価値がある内容ですし、デザイナーにとってももちろん参考になる内容です。

他にもこんなのもあります。

最近ホットな働き方についてのセッションですね。エンジニアリングというのはあらゆるところに関係するので、デブサミというのも決して技術だけの話に留まらないのです。

情報収集効率が良い

デブサミなどの大型イベントは情報収集効率が非常に良いです。先ほど紹介した通り非常に多岐にわたる内容を2日間でまとめ聞きすることができます。仮にもしこれを別々の勉強会で聴こうと思ったら相当な時間をかけねばなりませんが、デブサミであれば2日で済みます。また空き時間は休憩スペースで仕事できるのでリモートで作業しながらセッションに参加ということもできます。

プレゼンの参考にも

また、デブサミで発表される内容は相応に吟味されているものが多いので情報の質も高いです(ハズレもありますが)。有料セミナーほどではないかもしれませんが、控え目に見てもエンジニアイベントで最大規模のものなのでプレゼンテーターもよく練習しています。時間の使い方、スライドの見せ方、ウケの取り方など、プレゼンテーションの参考になります。

今、技術で何ができて何が難しいのかを知れる

デブサミでいろいろなセッションを聞くと「今は、ここまでできるんだな」とか「これはまだ技術的に難しいのか」といった感触を肌で感じられます。これが本当にありがたく、デザイナーにとっては引き出しの数が増やすネタになる生産性向上にも繋がります。

例えば、サイトにチャットのシステム埋め込んでユーザーの体験性を向上したり、機械学習を利用してユーザーに対してよりよい情報を提供する、など技術的に実現可能なネタを理解できていればサービスの改善幅が格段に広がります。さらに、デブサミではそう言った話を実際の体験談として教えてくれるので、先回りして失敗を回避でき、実現可能性を高めてくれます

また生産性でいえば、ここ数年浸透したDevOpsの動きなどに代表されるような事例は非常に参考になります。チャットオプスや、ツール導入によるコミュニケーション品質の向上・作業時間の圧縮、プロジェクト成功のコツなど。

弊社でもチャットオプスは導入していて非常に助かってますが、こういった事例は実際に話を聞いてみると、わかることもたくさんあります。

他社のサービス開発の裏側を見ることができる

他社のサービス開発ってどうなってるか興味ありませんか?自社ではこうしているけど他ではどうしているんだろう、と。こういった話はデブサミでは本当にいろいろな方が話してくれています。「スクラムやったけどうまくいかなかったよ」とか「trello使ってこんな感じでプロジェクト進められました」など。

また、エンジニアとデザイナーの共生について垣間見ることもできます。エンジニアからはデザイナーがどういう風に見えているのか、またどういう風に巻き込もうとしているのか。こういった自分たちに対しての第三者の目線を知る機会としてもデブサミは非常に良い場所になっています。

デザインとデザイン業界の相対化

デブサミに出てみると「なるほどエンジニアの世界はそうなっているのか。翻ってデザインの世界はどうだろう?」と考えさせられます。決してデザインの世界を揶揄するわけではありませんが、そうやって相対化することで見えてくることは必ずあります。それはデザインの強みや弱み、デザイン業界の課題やアドバンテージなど。

例えば、昨年の11月にAdobe Maxがありました。私も参加したのですが、正直面白いところもあったけれど残念なところも少なくありませんでした。デブサミなどと比較すると「もっとこういう要素があった方が良かったな」と思える点が多々ありました。こういう風に考えられることも(デブサミに限らず)、自分の領域とは違うところに顔を出すメリットなのかと思います。

エンジニアと話せるようになる

これはとても大きいですね。普段のコミュニケーションが変わってきます。

私はもともとコード書くのが好きというのもあり隔てなく話せる方だと思いますが、デブサミやGCP Next Tokyo(Googleの主催する大型イベント)に参加してエンジニアのみんなと一緒に先端の情報に触れるとまた格段と話しやすくなります。

  • 「あのセッションで聴いた内容いいよね」
  • 「もっとこういう技術使ってワークフロー改善したらいいかもね」

と言ったような。

あとはいくつものセッションを聴いていると、だんだんとエンジニアがどういう考え方をして何に重きを置くのかということを体感として理解できるようになります(そう信じている、という方が正しいかもしれませんが)。こういった共通感覚を醸成できるのも大きな収穫になると感じます。

いずれにせよ、エンジニアとデザイナーは協力することで良いものを生み出していくので、お互いのことを知るというのは大事という、至極当然な話なのですが。

おわりに:デザイン以外の領域にも触れるマインドがとても大事

デザイナーは気づいたらコミュニティーの内側に閉じこもってしまいがちです。自分の世界を大事にするというか。でも、私たちデザイナーが相対するのは「人」ですから、閉じこもらずに様々な領域、少なくても自身の近接領域であるエンジニアリングやマーケティングの世界を知ることを是非大事にしてもらいたいな、と思います。また、日々の発想を豊かにするためにまったく違う領域に興味を持つ好奇心は常に高く持ちたいな、と。

では、本日も最後までお読みいただきありがとうございました。

例によって当社では一緒に開発してくれるメンバーを募集しております。カジュアル面談も随時行っておりますので、「ちょっと話聞きたい」という方は、このブログのサイドバー下にあるアドレスか@YojiShirakiあたりにDMいただければと思います。採用サイトもありますので↓↓↓のバナーから是非どうぞ!

(過去記事)

Spark でUnit Testを書く

こんにちは、朴と申します。

本日はSpark-testing-baseを使ってSpark処理の単体テストの書き方について触れてみたいと思います。
ローカルで並列処理の単体テスト動かすのは少しハードル高く感じるかもしれませんが、
ちょっとした設定でスムーズに動かせたので、設定から簡単なテストまで書いてみたいと思います。

Spark-testing-baseの概要

ローカルでSparkのプログラムの単体テストを書く為のフレームワークです
複雑な設定をせず簡単にSparkプログラムの初期化、起動ができます。
簡単な紹介など、以下のリンクから確認できます。
Spark-testing-base

設定

とりあえず、公式サイトにある通り設定を行います。

  • sbtプロジェクトのbuild.sbtに以下のdependencyを追加します。
    ※2.2.0の部分は実際使うSparkのバージョンに合わせてください。
"com.holdenkarau" %% "spark-testing-base" % "2.2.0_0.8.0" % "test"


  • OutOfMemoryError 防止の為以下の設定も追加して置きます、メモリは適宜調整してください。
fork in Test := true
javaOptions ++= Seq("-Xms512M", "-Xmx2048M", "-XX:MaxPermSize=2048M", "-XX:+CMSClassUnloadingEnabled")


  • テストでのparallel 実行を無効にする
parallelExecution in Test := false

以上で設定完了です。

書いてみる1

続いて公式サイトのwikiにあるサンプルを一個書いて、動作確認をします。

class test extends FunSuite with DatasetSuiteBase {
  test("simple test") {
    val sqlCtx = sqlContext
    import sqlCtx.implicits._

    val input1 = sc.parallelize(List(1, 2, 3)).toDS
    assertDatasetEquals(input1, input1) // equal

    val input2 = sc.parallelize(List(4, 5, 6)).toDS
    intercept[org.scalatest.exceptions.TestFailedException] {
        assertDatasetEquals(input1, input2) // not equal
    }
  }
}

IntelliJ IDEA起動して動かしますと以下のエラーが出てました。

java.lang.NoClassDefFoundError: org/apache/hadoop/hive/conf/HiveConf$ConfVars
...
...
Caused by: java.lang.ClassNotFoundException: org.apache.hadoop.hive.conf.HiveConf$ConfVars

エラー内容でググってみたらどうやらdependencyが足りないようなので、以下を追加します。
sparkVersionはご自身の環境に合わせてください。

"org.apache.spark" %% "spark-hive" % sparkVersion % "test"

今度無事起動するかと思ったら違うエラーが出てました。 どうやらHiveSession起動時にローカルだとうまく行かないみたいですね。

java.lang.IllegalArgumentException: Error while instantiating 'org.apache.spark.sql.hive.HiveSessionStateBuilder':
...
...
Caused by: java.lang.RuntimeException: java.lang.RuntimeException: Error while running command to get file permissions : java.io.IOException: (null) entry in command string: null ls -F C:\tmp\hive

Spark Hiveをoffにすることでエラーは回避できるみたいなので、
上記のテストケースの一番最初に以下を追加します。

class test extends FunSuite with DatasetSuiteBase {
  override implicit def enableHiveSupport: Boolean = false  // 追加
  test("simple test") {
    val sqlCtx = sqlContext
    import sqlCtx.implicits._

    val input1 = sc.parallelize(List(1, 2, 3)).toDS
    assertDatasetEquals(input1, input1) // equal

    val input2 = sc.parallelize(List(4, 5, 6)).toDS
    intercept[org.scalatest.exceptions.TestFailedException] {
        assertDatasetEquals(input1, input2) // not equal
    }
  }
}

これで無事起動できました。

 主なクラスの紹介

  • SharedSparkContext
    SparkContextをローカルで使える形で提供

  • RDDComparisons
    RDD比較用クラス

  • DataFrameSuiteBase
    DataFrameのテスト用

  • DatasetSuitBase
    Datasetのテスト用

  • StreamingSuiteBase
    streamのテスト用

各クラス使い方は公式サイトのwikiに乗ってる通り直感的で分かりやすいので、ここでは割愛します。

自分のテストを書いてみる

いよいよご自身のテストを書きます。
以下のようなクラウドファンディングデータを読み込んでそのデータが期待とおりとなってるか確認します。
以下データ一部※

{
  "raised": {
    "currency": "USD",
    "amount": 1685
  },
  "goal": {
    "currency": "USD",
    "amount": 2000
  },
  "short_description": "to find a better/safer way to diagnose, monitor and guide those with EGID's on their life journey",
  "name": "EoE Chompers",
  "project_id": "193451"
}
{
  "raised": {
    "currency": "USD",
    "amount": 50
  },
  "goal": {
    "currency": "USD",
    "amount": 12000
  },
  "short_description": "Help provide 70 children with a new roof to keep them healthy and a boundary wall to keep them safe!",
  "name": "A New Roof and Safety Wall for 70 children",
  "project_id": "193469"
}

テストコード

class MyTest1 extends FunSuite with DatasetSuiteBase {
  override implicit def enableHiveSupport: Boolean = false

  test("count should be equal") {
    val ds1 = spark.read.json("c:\\temp\\cf_example_projects.json.gz")
    assertTrue(ds1.count() == 38080) // 実際Datasetのレコード件数とファイルの行数が一致するか
  }

  test("id should be unique") {
    val ds1 = spark.read.json("c:\\temp\\cf_example_projects.json.gz")
    val projectIdCount = ds1.select("project_id").distinct().count()
    assertTrue(projectIdCount == 38080)
  }
}

ちょっと進化させてみる

上のファイルを読み込む部分は以下のようにメソッド化して、このメソッドについてテストを書きます

object MyObject {
  case class Cf(projectId : String, name : String, shortDesc : String, currency : String, goalAmount: Double,raisedAmount:Double)
  def json2ds(spark:SparkSession,path:String) : Dataset[Cf] = {
    import spark.implicits._
    val ds1 = spark.read.json(path)
    ds1.map { r =>
      Cf(
        r.getAs[String]("project_id"),
        r.getAs[String]("name"),
        r.getAs[String]("short_description"),
        r.getAs[Row]("goal").getAs[String]("currency"),
        r.getAs[Row]("goal").getAs[Double]("amount"),
        r.getAs[Row]("raised").getAs[Double]("amount")
      )
    }
  }
}


class MyTest2 extends FunSuite with DatasetSuiteBase {
  override implicit def enableHiveSupport: Boolean = false

  test("one of selected record should be exist") {
    val ds1 = MyObject.json2ds(spark,"c:\\temp\\cf_example_projects.json.gz")
    val result = ds1.where($"projectId".equalTo("193469"))
    val excepted = Seq(Cf("193469","A New Roof and Safety Wall for 70 children","Help provide 70 children with a new roof to keep them healthy and a boundary wall to keep them safe!","USD",15000d,50d)).toDS()
    assertDatasetEquals(excepted,result)
  }

  test("no such record") {
    val ds1 = MyObject.json2ds(spark,"c:\\temp\\cf_example_projects.json.gz")
    val result = ds1.where($"projectId".equalTo("xxxxxx"))
    val excepted = Seq(Cf("xxxxxx","A New Roof and Safety Wall for 70 children","Help provide 70 children with a new roof to keep them healthy and a boundary wall to keep them safe!","USD",12000d,50d)).toDS()
    intercept[org.scalatest.exceptions.TestFailedException] {
      assertDatasetEquals(result, excepted)
    }
  }
}

テストデータ作成用のクラス(Generator)も

使う場面がちょっと微妙ですが、テストデータ用のDataset、DataFrameを生成することも出来ます。

サンプルそのまま張り付けておきますが、こんな感じです。
動かすにはhttps://github.com/rickynils/scalacheck/blob/master/doc/UserGuide.mdというものが必要らしいです。

class SampleDatasetGeneratorTest extends FunSuite with SharedSparkContext with Checkers {
  test("test generating Datasets[String]") {
    val sqlContext = new SQLContext(sc)
    import sqlContext.implicits._

    val property =
      forAll(DatasetGenerator.genDataset[String](sqlContext)(Arbitrary.arbitrary[String])) {
        dataset => dataset.map(_.length).count() == dataset.count()
      }

    check(property)
  }

}

最後に

Sparkの単体テストについてはメジャーなやつがないのが現状だと認識してますので、
ここで紹介したのは一つの選択肢としてみて頂ければと思います
上記以外にもいくつか選択肢があるみたいですので、色々試してみるとご自身に合うものを見つけられるでしょう。

弊社ではエンジニア・デザイナー絶賛大募集中ですので、興味ある方は気軽にお話でも聞いてみませんか?

DB3分クッキング Neo4jではじめるグラフデータベース入門

f:id:astamuse:20180123182120j:plain

こんにちは、福田 a.k.a. FDKです。

バルトークのアレグロ・バルバロを聴きながらバルクロードを実行しています。

点と点をこねくり回していると、イノヴェイションが生まれることがあります。

そう、まさに “Connecting the Dots” の瞬間です。

はじめに

グラフは、点と点を線で繋いだ構造で、この世界の至るところに見られます。 点同士を結ぶ線に向きや重みを持たせて関係性を表現することで、様々な探索ができるようになります。

例えば、SNS。人を点、友達関係を線で表し、友達関係の連鎖を辿り新たな関係を知るといったことはイメージしやすいと思います。

ボキャブラリ。わたしたちがものごとを考えるとき、言葉は欠かせません。キーワード同士にも何らかの関係があり、豊かな語彙は文脈とともに思索の飛び石となります。

ここでは、特許文書に現れるキーワードとその近接関係、そしてキーワードが現れる文脈との関係データをグラフ化して探索をしてみます。

Neo4jとは

グラフデータベースは、グラフ構造のデータの格納と検索に特化したデータベースです。商用、オープンソース、様々なプロダクトがあり、広く使われています。

Neo4jは、Neo Technology社により開発されたデータベースで、2010年にバージョン1.0がリリースされました。2018年1月23日時点での最新の安定バージョンは3.3.2です。

特徴として以下があげられます。

  • Cypherと呼ばれる宣言型グラフ向けクエリ言語
  • ACIDトランザクションのサポート
  • プロパティグラフ(点と線それぞれにkey-valueの形式で複数の属性を持たせられる)
  • Javaで実装されている
  • Boltというバイナリプロトコル(3.0以降)
  • 豊富なドライバ(.NET、Java、JavaScript、Python、Ruby、 PHP、R、Go、Erlang、C/C++、Clojure、Perl, Haskellなど)
  • 内部的にLuceneを使用
  • コミュニティ版とエンタープライズ版
  • GPLv3 及び AGPLv3 / 商用

*1

レシピ編

データ

  • キーワードのデータ(4,722,057行)
  • キーワード同士の関連データ(136,802,075行)
  • 課題文脈のデータ(22,444行)
  • キーワードと課題の関連データ(114,832,650行)

手元の実験用テストデータ。日本国内特許公報データをもとに、Hadoop、Word2vecなどを使って生成したデータになります。アスタミューゼにはデータがたくさんあり、データからデータを生成できます。

環境・ミドルウェア

  • GCP n1-highmem-8 preemptible*2 (8 vCPU, 52GB RAM, SSD storage 100 GB)
  • Linux (Ubuntu 16.04.3 LTS)
  • Neo4j 3.4.0 alpha06*3

設計

Neo4jで扱うプロパティグラフの形式に落とし込みます。

まず、キーワードと、課題文脈のデータ*4をNodeに対応させます。

そして、Node同士の関係をRelationshipに対応させます。関係の向きと重み、ラベルを定義します。

角丸の四角がNode(点)、矢印がRelation(線)になります。

f:id:astamuse:20180123193603p:plain

準備編

マニュアル*5を参照しながらセットアップします。

ここではUbuntu 16.04.3 LTSにNeo4j 3.4.0 alpha06をインストールします。

インストール

$ wget -O - https://debian.neo4j.org/neotechnology.gpg.key | sudo apt-key add -
$ echo 'deb http://debian.neo4j.org/repo testing/' | sudo tee -a /etc/apt/sources.list.d/neo4j.list
$ sudo apt-get update
$ sudo apt-get install neo4j=3.4.0.alpha06

*6

設定

設定ファイル/etc/neo4j/neo4j.confの編集

35,36c35,36
< #dbms.memory.heap.initial_size=512m
< #dbms.memory.heap.max_size=512m
---
> dbms.memory.heap.initial_size=16G
> dbms.memory.heap.max_size=16G
46c46
< #dbms.memory.pagecache.size=10g
---
> dbms.memory.pagecache.size=32g
54c54
< #dbms.connectors.default_listen_address=0.0.0.0
---
> dbms.connectors.default_listen_address=0.0.0.0
< #dbms.threads.worker_count=
---
> dbms.threads.worker_count=8

調理編

CSVの作成

Neo4jには大量のデータをCSVから効率良くロードするためのneo4j-admin importコマンド*7があります。このコマンドはデータの初期ロード専用で、データベースディレクトリが空でないと実行できませんが、高速にデータをロードできます。既存のデータベースへのデータのバルクロードには別途LOAD CSVコマンド*8を使用します。

Node、RelationshipのCSVファイルを複数用意し、一括でロードします。それぞれのCSVファイルのヘッダに、ロード先のスキーマを表現します。詳しくはマニュアル*9にあります。

ここでは、前述の設計に従って、CSVファイルを用意します。

keyword.csv:KeywordのNodeデータ

id:ID(Keyword-ID),name:string,:LABEL
12852111,プリプリ感,Keyword
115168,プリプレグ,Keyword
10515289,プリプレグFRPシート,Keyword
10515208,プリプレグアセンブリ,Keyword
12852112,プリプレグカセット,Keyword
10515209,プリプレグクロス,Keyword
10515210,プリプレグシート,Keyword

issue_fterm_context.csv:FTermのNodeデータ

id:ID(FTerm-ID),code,context,:LABEL
1,2B022EA00,植物の栽培/化学物質の処理目的,FTerm
2,2B022EA01,植物の栽培/化学物質の処理目的/生長調節,FTerm
3,2B022EA02,植物の栽培/化学物質の処理目的/生長調節/種なし果実の作成,FTerm
4,2B022EA03,植物の栽培/化学物質の処理目的/果実、野菜の食味、色付きの向上,FTerm
5,2B022EA10,植物の栽培/化学物質の処理目的/その他,FTerm
6,2B026BB00,海藻の栽培/支柱の目的、機能,FTerm
7,2B026BB01,海藻の栽培/支柱の目的、機能/強度を増す,FTerm
8,2B026BB02,海藻の栽培/支柱の目的、機能/打ち込み引きぬき,FTerm
9,2B026BB03,海藻の栽培/支柱の目的、機能/倒伏防止,FTerm

Nodeデータのフォーマットは、(属性[:型],)+:LABELのような形になります。:IDは識別子であることを表し、Node毎に必ず指定します。:IDの後ろの(Keyword-ID)は、IDの名前空間を指定しています。デフォルトではNodeの名前空間は一つになります。リレーショナル・データベースでよくみられるように数値型のIDを持つエンティティが複数ある場合には、それぞれのIDの名前空間を分ける必要があります。

similarity.csv:SIMILAR_TOのRelationsipデータ

:START_ID(Keyword-ID),score:double,:END_ID(Keyword-ID),:TYPE
14384010,0.846703052521,14251003,SIMILAR_TO
14164776,0.840930700302,14251003,SIMILAR_TO
11690273,0.817037463188,14251003,SIMILAR_TO
10211878,0.808667063713,14251003,SIMILAR_TO
10446057,0.798547029495,14251003,SIMILAR_TO
13343895,0.795734345913,14251003,SIMILAR_TO
14335569,0.789334237576,14251003,SIMILAR_TO
12207055,0.788067042828,14251003,SIMILAR_TO
12698152,0.784716844559,14251003,SIMILAR_TO

keyword_issue.csv:RESOLVEのRelationshipデータ

:START_ID(Keyword-ID),n:int,:END_ID(FTerm-ID),:TYPE
12338970,1,2,RESOLVE
42045,1,2,RESOLVE
10181692,1,2,RESOLVE
12637528,1,2,RESOLVE
12676513,1,2,RESOLVE
109171,1,2,RESOLVE
10799840,1,2,RESOLVE
13335687,1,2,RESOLVE
11029079,8,2,RESOLVE

データロード

そして、以下のような簡易ロードスクリプトを用意しました。

#!/bin/bash

systemctl stop neo4j

rm -rf /var/lib/neo4j/data/databases/graph.db/*

NEO4J_DEBUG=true HEAP_SIZE=16g neo4j-admin import --nodes issue_fterm_context.csv --nodes keyword.csv --relation
ships similarity.csv --relationships keyword_issue.csv --ignore-missing-nodes=true --ignore-duplicate-nodes=true
-id-type=INTEGER

chown -R neo4j:neo4j /var/lib/neo4j/data/databases/graph.db/

systemctl start neo4j

実行すると、進捗とサマリーが表示されます。

Neo4j version: 3.4.0-alpha06
Importing the contents of these files into /var/lib/neo4j/data/databases/graph.db:
Nodes:
 /var/tmp/blog/issue_fterm_context.csv

 /var/tmp/blog/keyword.csv
Relationships:
 /var/tmp/blog/similarity.csv

 /var/tmp/blog/keyword_issue.csv

Available resources:
 Total machine memory: 51.10 GB
 Free machine memory: 49.98 GB
 Max heap memory : 15.33 GB
 Processors: 8
 Configured max memory: 31.18 GB

Import starting 2018-01-23 04:05:24.396+0000
 Estimated number of nodes: 7.29 M
 Estimated number of node properties: 14.63 M
 Estimated number of relationships: 145.48 M
 Estimated number of relationship properties: 145.48 M
 Estimated disk space usage: 10.86 GB
 Estimated required memory usage: 569.89 MB

Interactive command list (end with ENTER):
 c: Print more detailed information about current stage
 i: Print more detailed information

(1/4) Node import 2018-01-23 04:05:24.418+0000
 Estimated number of nodes: 7.29 M
 Estimated disk space usage: 710.50 MB
 Estimated required memory usage: 569.89 MB
.......... .......... .......... .......... .......... 5%
.......... .......... .......... .......... .......... 10%
.......... .......... .......... .......... .......... 15%
.......... .......... .......... .......... .......... 20%
.......... .......... .......... .......... .......... 25%
.......... .......... .......... .......... .......... 30%
.......... .......... .......... .......... .......... 35%
.......... .......... .......... .......... .......... 40%
.......... .......... .......... .......... .......... 45%
.......... .......... .......... .......... .......... 50%
.......... .......... .......... .......... .......... 55%
.......... .......... .......... .......... .......... 60%
.......... .......... .......... .......... .......... 65%
.......... .......... .......... .......... .......... 70%
.......... .......... .......... .......... .......... 75%
.......... .......... .......... .......... .......... 80%
.......... .......... .......... .......... .......... 85%
.......... .......... .......... .......... .......... 90%
.......... .......... .......... .......... .......... 95%
.......... .......... .......... .......... .......... 100%

(2/4) Relationship import 2018-01-23 04:05:29.298+0000
 Estimated number of relationships: 145.48 M
 Estimated disk space usage: 10.16 GB
 Estimated required memory usage: 534.38 MB
.......... .......... .......... .......... .......... 5%
.......... .......... .......... .......... .......... 10%
.......... .......... .......... .......... .......... 15%
.......... .......... .......... .......... .......... 20%
.......... .......... .......... .......... .......... 25%
.......... .......... .......... .......... .......... 30%
.......... .......... .......... .......... .......... 35%
.......... .......... .......... .......... .......... 40%
.......... .......... .......... .......... .......... 45%
.......... .......... .......... .......... .......... 50%
.......... .......... .......... .......... .......... 55%
.......... .......... .......... .......... .......... 60%
.......... .......... .......... .......... .......... 65%
.......... .......... .......... .......... .......... 70%
.......... .......... .......... .......... .......... 75%
.......... .......... .......... .......... .......... 80%
.......... .......... .......... .......... .......... 85%
.......... .......... .......... .......... .......... 90%
.......... .......... .......... .......... .......... 95%
.......... .......... .......... .......... .........(3/4) Relationship linking 2018-01-23 04:08:40.284+0000
 Estimated required memory usage: 527.90 MB
.......... .......... .......... .......... .......... 5%
.......... .......... .......... .......... .......... 10%
.......... .......... .......... .......... .......... 15%
.......... .......... .......... .......... .......... 20%
.......... .......... .......... .......... .......... 25%
.......... .......... .......... .......... .......... 30%
.......... .......... .......... .......... .......... 35%
.......... .......... .......... .......... .......... 40%
.......... .......... .......... .......... .......... 45%
.......... .......... .......... .......... .......... 50%
.......... .......... .......... .......... .......... 55%
.......... .......... .......... .......... .......... 60%
.......... .......... .......... .......... .......... 65%
.......... .......... .......... .......... .......... 70%
.......... .......... .......... .......... .......... 75%
.......... .......... .......... .......... .......... 80%
.......... .......... .......... .......... .......... 85%
.......... .......... .......... .......... .......... 90%
.......... .......... .......... .......... .......... 95%
.......... .......... .......... .......... .......... 100%

(4/4) Post processing 2018-01-23 04:09:46.174+0000
 Estimated required memory usage: 478.13 MB
.......... .......... .......... .......... .......... 5%
.......... .......... .......... .......... .......... 10%
.......... .......... .......... .......... .......... 15%
.......... .......... .......... .......... .......... 20%
.......... .......... .......... .......... .......... 25%
.......... .......... .......... .......... .......... 30%
.......... .......... .......... .......... .......... 35%
.......... .......... .......... .......... .......... 40%
.......... .......... .......... .......... .......... 45%
.......... .......... .......... .......... .......... 50%
.......... .......... .......... .......... .......... 55%
.......... .......... .......... .......... .......... 60%
.......... .......... .......... .......... .......... 65%
.......... .......... .......... .......... .......... 70%
.......... .......... .......... .......... .......... 75%
.......... .......... .......... .......... .......... 80%
.......... .......... .......... .......... .......... 85%
.......... .......... .......... .......... .......... 90%
.......... .......... .......... .......... .......... 95%
.......... .......... .......... .......... .......... 100%


IMPORT DONE in 4m 35s 487ms.  
Imported:
 4744499 nodes
 145399772 relationships
 154911213 properties
Peak memory usage: 632.11 MB

4分半程でロードが完了しました。単純計算で約93万行/秒のスループットです。

また、以前のバージョンよりも表示がわかりやすく、進捗の視認性がよくなっています。

インデックスの作成

neo4j-admin importで初期ロードしたデータには、インデックスは作成されていないため、個別に作成します。

cypher-shellというインタラクティブなシェルを使います。*10

$ cypher-shell  
username: neo4j
password: ********
Connected to Neo4j 3.4.0-alpha06 at bolt://localhost:7687 as user neo4j.
Type :help for a list of available commands or :exit to exit the shell.
Note that Cypher queries must end with a semicolon.
neo4j> MATCH (k: Keyword {name: "プリプレグ"}) RETURN k;
+----------------------------------------+
| k                                      |
+----------------------------------------+
| (:Keyword {name: "プリプレグ", id: 115168}) |
+----------------------------------------+

1 row available after 113 ms, consumed after another 4509 ms
neo4j> MATCH (k: Keyword {name: "プリプレグ"}) RETURN k;
+----------------------------------------+
| k                                      |
+----------------------------------------+
| (:Keyword {name: "プリプレグ", id: 115168}) |
+----------------------------------------+

1 row available after 5 ms, consumed after another 3888 ms
neo4j> CREATE INDEX ON :Keyword(name);
0 rows available after 54 ms, consumed after another 0 ms
Added 1 indexes

CREATE INDEXを実行すると、インデックスは非同期で作成されます。

ステータスはログに出力されます。

2018-01-23 04:13:24.092+0000 INFO [o.n.k.i.a.i.IndexPopulationJob] Index population started: [:Keyword(name) [pr
ovider: {key=lucene+native, version=1.0}]]
2018-01-23 04:13:40.480+0000 INFO [o.n.k.i.a.i.IndexPopulationJob] Completed node store scan. Flushing all pendi
ng updates.
BatchingMultipleIndexPopulator{activeTasks=5, executor=java.util.concurrent.ThreadPoolExecutor@2b76dd88[Running,
pool size = 7, active threads = 5, queued tasks = 0, completed tasks = 468], batchedUpdates = [0 updates], queu
edUpdates = 0}
2018-01-23 04:13:40.481+0000 INFO [o.n.k.i.a.i.IndexPopulationJob] Shutting down executor.
BatchingMultipleIndexPopulator{activeTasks=5, executor=java.util.concurrent.ThreadPoolExecutor@2b76dd88[Running,
pool size = 7, active threads = 5, queued tasks = 0, completed tasks = 469], batchedUpdates = [0 updates], queu
edUpdates = 0}
2018-01-23 04:13:46.163+0000 INFO [o.n.k.i.a.i.IndexPopulationJob] Index population completed. Index is now onli
ne: [:Keyword(name) [provider: {key=lucene+native, version=1.0}]]

インデックスの作成が完了したところで、再度検索してみます。

neo4j> MATCH (k: Keyword {name: "プリプレグ"}) RETURN k;
+----------------------------------------+
| k                                      |
+----------------------------------------+
| (:Keyword {name: "プリプレグ", id: 115168}) |
+----------------------------------------+

1 row available after 62 ms, consumed after another 1 ms
neo4j> MATCH (k: Keyword {name: "プリプレグ"}) RETURN k;
+----------------------------------------+
| k                                      |
+----------------------------------------+
| (:Keyword {name: "プリプレグ", id: 115168}) |
+----------------------------------------+

1 row available after 2 ms, consumed after another 1 ms
neo4j>

試食編

プリプレグ

ところで、「プリプレグ」とは何でしょう。食べ物ではなさそうです。あまり耳馴染みがない方も多いかもしれません。私もその一人です。

初めて聞くキーワードを、周辺のキーワードと、キーワードが寄与している文脈から、おおよその見当をつけられるかもしれません。

早速、WebUI*11にアクセスし、クエリを実行してみます。

MATCH (k:Keyword {name: "プリプレグ"})-[s:SIMILAR_TO *1..3]-(l) RETURN DISTINCT s,l,k LIMIT 10

f:id:astamuse:20180123191853p:plain

朧げながら、プリプレグの人となりが見えてきます。わりと硬派な印象です。

今度は、周辺のキーワードに手を伸ばしつつ、関連する課題を探索してみます。

MATCH (k:Keyword {name: "プリプレグ"})-[s:SIMILAR_TO]-(l:Keyword)
WITH k, s, l ORDER BY s.score DESC LIMIT 100
MATCH (k)-[s]-(l)-[r:RESOLVE]->(f:FTerm)
WITH DISTINCT k, s, l, r, f ORDER BY r.n DESC LIMIT 20
RETURN k, s, l, r, f

グラフ表示

f:id:astamuse:20180123183837p:plain

テキスト表示

╒════════════════════════════╤════════════════════════╤═══════════════════════════════╤════════╤══════════════════════════════════════════════════════════════════════╕
│"k"                         │"s"                     │"l"                            │"r"     │"f"                                                                   │
╞════════════════════════════╪════════════════════════╪═══════════════════════════════╪════════╪══════════════════════════════════════════════════════════════════════╡
│{"name":"プリプレグ","id":115168}│{"score":0.641988456249}│{"name":"熱硬化性樹脂","id":13947024}│{"n":50}│{"context":"接着剤、接着方法/物理(化学)的性質又は目的、効果/機械的特性","code":"4J040LA06","id":1│
│                            │                        │                               │        │4260}                                                                 │
├────────────────────────────┼────────────────────────┼───────────────────────────────┼────────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"プリプレグ","id":115168}│{"score":0.641988456249}│{"name":"熱硬化性樹脂","id":13947024}│{"n":45}│{"context":"接着剤、接着方法/物理(化学)的性質又は目的、効果/電気磁気特性","code":"4J040LA09","id":│
│                            │                        │                               │        │14263}                                                                │
├────────────────────────────┼────────────────────────┼───────────────────────────────┼────────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"プリプレグ","id":115168}│{"score":0.641988456249}│{"name":"熱硬化性樹脂","id":13947024}│{"n":45}│{"context":"接着剤、接着方法/物理(化学)的性質又は目的、効果/温度特性又は熱特性","code":"4J040LA08","i│
│                            │                        │                               │        │d":14262}                                                             │
├────────────────────────────┼────────────────────────┼───────────────────────────────┼────────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"プリプレグ","id":115168}│{"score":0.641988456249}│{"name":"熱硬化性樹脂","id":13947024}│{"n":43}│{"context":"多層プリント配線板の製造/目的課題効果/機械的特性に関するもの","code":"5E346HH11","id":1│
│                            │                        │                               │        │7583}                                                                 │
├────────────────────────────┼────────────────────────┼───────────────────────────────┼────────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"プリプレグ","id":115168}│{"score":0.641988456249}│{"name":"熱硬化性樹脂","id":13947024}│{"n":30}│{"context":"接着剤、接着方法/物理(化学)的性質又は目的、効果/分子量又はその関連特性","code":"4J040LA01",│
│                            │                        │                               │        │"id":14255}                                                           │
├────────────────────────────┼────────────────────────┼───────────────────────────────┼────────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"プリプレグ","id":115168}│{"score":0.641988456249}│{"name":"熱硬化性樹脂","id":13947024}│{"n":29}│{"context":"電場又は磁場に対する装置又は部品の遮蔽/目的/電(磁)波シールド電磁シールド","code":"5E321GG05"│
│                            │                        │                               │        │,"id":17466}                                                          │
├────────────────────────────┼────────────────────────┼───────────────────────────────┼────────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"プリプレグ","id":115168}│{"score":0.641988456249}│{"name":"熱硬化性樹脂","id":13947024}│{"n":29}│{"context":"印刷回路の非金属質の保護被覆/目的効果/その他","code":"5E314GG26","id":17427}   │
├────────────────────────────┼────────────────────────┼───────────────────────────────┼────────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"プリプレグ","id":115168}│{"score":0.584715306759}│{"name":"ワニス","id":145746}     │{"n":29}│{"context":"電動機、発電機の製造/目的/製造,組立","code":"5H615AA01","id":20027}       │
├────────────────────────────┼────────────────────────┼───────────────────────────────┼────────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"プリプレグ","id":115168}│{"score":0.641988456249}│{"name":"熱硬化性樹脂","id":13947024}│{"n":28}│{"context":"印刷回路に対する電気部品等の電気的接続/目的効果/はんだ付け性の改良","code":"5E319GG03","id│
│                            │                        │                               │        │":17455}                                                              │
├────────────────────────────┼────────────────────────┼───────────────────────────────┼────────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"プリプレグ","id":115168}│{"score":0.641988456249}│{"name":"熱硬化性樹脂","id":13947024}│{"n":27}│{"context":"多層プリント配線板の製造/目的課題効果/製造生産に関するもの/歩留生産性の向上","code":"5E346HH33│
│                            │                        │                               │        │","id":17596}                                                         │
├────────────────────────────┼────────────────────────┼───────────────────────────────┼────────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"プリプレグ","id":115168}│{"score":0.641988456249}│{"name":"熱硬化性樹脂","id":13947024}│{"n":26}│{"context":"接着剤、接着方法/物理(化学)的性質又は目的、効果/結晶関連特性","code":"4J040LA02","id":│
│                            │                        │                               │        │14256}                                                                │
├────────────────────────────┼────────────────────────┼───────────────────────────────┼────────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"プリプレグ","id":115168}│{"score":0.791278362274}│{"name":"積層板","id":348376}     │{"n":25}│{"context":"プリント基板への印刷部品(厚膜薄膜部品)/目的,効果/その他","code":"4E351GG20","id":13│
│                            │                        │                               │        │245}                                                                  │
├────────────────────────────┼────────────────────────┼───────────────────────────────┼────────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"プリプレグ","id":115168}│{"score":0.641988456249}│{"name":"熱硬化性樹脂","id":13947024}│{"n":25}│{"context":"電動機、発電機の製造/目的/製造,組立","code":"5H615AA01","id":20027}       │
├────────────────────────────┼────────────────────────┼───────────────────────────────┼────────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"プリプレグ","id":115168}│{"score":0.791278362274}│{"name":"積層板","id":348376}     │{"n":23}│{"context":"プリント配線の製造(2)/目的効果/密着性の改良/導体とプリント板の基板","code":"5E343GG02","│
│                            │                        │                               │        │id":17545}                                                            │
├────────────────────────────┼────────────────────────┼───────────────────────────────┼────────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"プリプレグ","id":115168}│{"score":0.641988456249}│{"name":"熱硬化性樹脂","id":13947024}│{"n":23}│{"context":"多層プリント配線板の製造/目的課題効果/電気的特性に関するもの/電気的接続性","code":"5E346HH07"│
│                            │                        │                               │        │,"id":17581}                                                          │
├────────────────────────────┼────────────────────────┼───────────────────────────────┼────────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"プリプレグ","id":115168}│{"score":0.641988456249}│{"name":"熱硬化性樹脂","id":13947024}│{"n":20}│{"context":"繊維製品への有機化合物の付着処理/目的,効果/接着","code":"4L033AC11","id":14648} │
├────────────────────────────┼────────────────────────┼───────────────────────────────┼────────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"プリプレグ","id":115168}│{"score":0.641988456249}│{"name":"熱硬化性樹脂","id":13947024}│{"n":19}│{"context":"多層プリント配線板の製造/目的課題効果/その他","code":"5E346HH40","id":17597}   │
├────────────────────────────┼────────────────────────┼───────────────────────────────┼────────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"プリプレグ","id":115168}│{"score":0.791278362274}│{"name":"積層板","id":348376}     │{"n":17}│{"context":"多層プリント配線板の製造/目的課題効果/機械的特性に関するもの","code":"5E346HH11","id":1│
│                            │                        │                               │        │7583}                                                                 │
├────────────────────────────┼────────────────────────┼───────────────────────────────┼────────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"プリプレグ","id":115168}│{"score":0.641988456249}│{"name":"熱硬化性樹脂","id":13947024}│{"n":17}│{"context":"印刷回路の非金属質の保護被覆/目的効果/生産性向上","code":"5E314GG24","id":17426} │
├────────────────────────────┼────────────────────────┼───────────────────────────────┼────────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"プリプレグ","id":115168}│{"score":0.641988456249}│{"name":"熱硬化性樹脂","id":13947024}│{"n":15}│{"context":"半導体又は固体装置の封緘,被覆構造と材料/用途又は特殊目的/光半導体用","code":"4M109GA01","i│
│                            │                        │                               │        │d":14812}                                                             │
└────────────────────────────┴────────────────────────┴───────────────────────────────┴────────┴──────────────────────────────────────────────────────────────────────┘

クエリの結果を解釈して評価するためには、別途何らかの判断基準が必要そうです。

門外漢の私には少々荷が重いので、いささか心得のある、ラーメンというキーワードに換えてクエリを実行してみることにします。

ラーメン

MATCH (k:Keyword {name: "ラーメン"})-[s:SIMILAR_TO]-(l:Keyword)
WITH k, s, l ORDER BY s.score DESC LIMIT 100
MATCH (k)-[s]-(l)-[r:RESOLVE]->(f:FTerm)
WITH DISTINCT k, s, l, r, f ORDER BY r.n DESC LIMIT 20
RETURN k, s, l, r, f

グラフ表示 f:id:astamuse:20180123183933p:plain

テキスト表示

╒═══════════════════════════╤════════════════════════╤═══════════════════════════════════╤═══════╤══════════════════════════════════════════════════════════════════════╕
│"k"                        │"s"                     │"l"                                │"r"    │"f"                                                                   │
╞═══════════════════════════╪════════════════════════╪═══════════════════════════════════╪═══════╪══════════════════════════════════════════════════════════════════════╡
│{"name":"ラーメン","id":137294}│{"score":0.617753505707}│{"name":"包装食品","id":10958102}      │{"n":3}│{"context":"包装体/目的,機能(1)特定の環境の維持/その他/包装体/その他/包装体/その他/包装体/その他","code":"│
│                           │                        │                                   │       │3E067GD10","id":5974}                                                 │
├───────────────────────────┼────────────────────────┼───────────────────────────────────┼───────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"ラーメン","id":137294}│{"score":0.336226522923}│{"name":"喫食用容器入り冷凍麺","id":13427756}│{"n":3}│{"context":"穀類誘導製品3(麺類)/目的/即席化","code":"4B046LC11","id":12085}        │
├───────────────────────────┼────────────────────────┼───────────────────────────────────┼───────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"ラーメン","id":137294}│{"score":0.617753505707}│{"name":"包装食品","id":10958102}      │{"n":2}│{"context":"食品の保存(凍結・冷却・乾燥を除く)/使用目的/抗微生物","code":"4B021MC01","id":1180│
│                           │                        │                                   │       │3}                                                                    │
├───────────────────────────┼────────────────────────┼───────────────────────────────────┼───────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"ラーメン","id":137294}│{"score":0.492829829454}│{"name":"ゲル状調味料","id":10169798}    │{"n":2}│{"context":"ゼリ−、ジャム、シロップ/目的/テクスチャーの改善","code":"4B041LC03","id":12012} │
├───────────────────────────┼────────────────────────┼───────────────────────────────────┼───────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"ラーメン","id":137294}│{"score":0.492829829454}│{"name":"ゲル状調味料","id":10169798}    │{"n":2}│{"context":"種実、スープ、その他の食品/目的/味,香りの改善","code":"4B036LC01","id":11983}  │
├───────────────────────────┼────────────────────────┼───────────────────────────────────┼───────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"ラーメン","id":137294}│{"score":0.617753505707}│{"name":"包装食品","id":10958102}      │{"n":2}│{"context":"袋/目的機能/内容物の保存性向上","code":"3E064EA18","id":5883}           │
├───────────────────────────┼────────────────────────┼───────────────────────────────────┼───────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"ラーメン","id":137294}│{"score":0.617753505707}│{"name":"包装食品","id":10958102}      │{"n":1}│{"context":"肉類、卵、魚製品/目的/呈味の改善","code":"4B042AC03","id":12021}         │
├───────────────────────────┼────────────────────────┼───────────────────────────────────┼───────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"ラーメン","id":137294}│{"score":0.617753505707}│{"name":"包装食品","id":10958102}      │{"n":1}│{"context":"高周波加熱[構造]/目的/電磁波の漏洩防止","code":"3K090LA04","id":10994}     │
├───────────────────────────┼────────────────────────┼───────────────────────────────────┼───────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"ラーメン","id":137294}│{"score":0.617753505707}│{"name":"包装食品","id":10958102}      │{"n":1}│{"context":"肉類、卵、魚製品/目的/保存性の改善","code":"4B042AC06","id":12024}        │
├───────────────────────────┼────────────────────────┼───────────────────────────────────┼───────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"ラーメン","id":137294}│{"score":0.617753505707}│{"name":"包装食品","id":10958102}      │{"n":1}│{"context":"基本的包装技術VII(真空包装)/目的/その他","code":"3E053JA10","id":5838}    │
├───────────────────────────┼────────────────────────┼───────────────────────────────────┼───────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"ラーメン","id":137294}│{"score":0.617753505707}│{"name":"包装食品","id":10958102}      │{"n":1}│{"context":"高周波加熱[構造]/目的/加熱効率向上又は省電力","code":"3K090AA02","id":10977}  │
├───────────────────────────┼────────────────────────┼───────────────────────────────────┼───────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"ラーメン","id":137294}│{"score":0.617753505707}│{"name":"包装食品","id":10958102}      │{"n":1}│{"context":"基本的包装技術VII(真空包装)/目的/高速化","code":"3E053JA01","id":5829}    │
├───────────────────────────┼────────────────────────┼───────────────────────────────────┼───────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"ラーメン","id":137294}│{"score":0.617753505707}│{"name":"包装食品","id":10958102}      │{"n":1}│{"context":"袋/目的機能/その他","code":"3E064EA30","id":5888}                 │
├───────────────────────────┼────────────────────────┼───────────────────────────────────┼───────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"ラーメン","id":137294}│{"score":0.617753505707}│{"name":"包装食品","id":10958102}      │{"n":1}│{"context":"基本的包装技術VII(真空包装)/目的/ガス置換率の向上","code":"3E053JA03","id":5831│
│                           │                        │                                   │       │}                                                                     │
├───────────────────────────┼────────────────────────┼───────────────────────────────────┼───────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"ラーメン","id":137294}│{"score":0.617753505707}│{"name":"包装食品","id":10958102}      │{"n":1}│{"context":"袋/目的機能/排出容易性","code":"3E064EA12","id":5877}               │
├───────────────────────────┼────────────────────────┼───────────────────────────────────┼───────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"ラーメン","id":137294}│{"score":0.617753505707}│{"name":"包装食品","id":10958102}      │{"n":1}│{"context":"袋/目的機能/経済性","code":"3E064EA01","id":5867}                 │
├───────────────────────────┼────────────────────────┼───────────────────────────────────┼───────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"ラーメン","id":137294}│{"score":0.617753505707}│{"name":"包装食品","id":10958102}      │{"n":1}│{"context":"加熱調理器/目的、効果/衛生性、外観","code":"4B055BA51","id":12144}        │
├───────────────────────────┼────────────────────────┼───────────────────────────────────┼───────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"ラーメン","id":137294}│{"score":0.617753505707}│{"name":"包装食品","id":10958102}      │{"n":1}│{"context":"誘導加熱調理器/目的、効果〔回路装置〕/回路素子/インバータ/表示,監視装置/誘導加熱調理器/非物理量※/基準値/構│
│                           │                        │                                   │       │造対象の処理態様※/使い勝手,判り易さ","code":"3K051AD39","id":10504}                   │
├───────────────────────────┼────────────────────────┼───────────────────────────────────┼───────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"ラーメン","id":137294}│{"score":0.617753505707}│{"name":"包装食品","id":10958102}      │{"n":1}│{"context":"包装体/目的,機能(1)特定の環境の維持/その他/包装体/その他/包装体/その他/包装体/風味,香気保持","cod│
│                           │                        │                                   │       │e":"3E067GD02","id":5966}                                             │
├───────────────────────────┼────────────────────────┼───────────────────────────────────┼───────┼──────────────────────────────────────────────────────────────────────┤
│{"name":"ラーメン","id":137294}│{"score":0.617753505707}│{"name":"包装食品","id":10958102}      │{"n":1}│{"context":"食品の調整及び処理一般/目的/その他","code":"4B035LC16","id":11981}        │
└───────────────────────────┴────────────────────────┴───────────────────────────────────┴───────┴──────────────────────────────────────────────────────────────────────┘

インスタントラーメンの製造に関する課題であることがわかります。

以上、簡単ですが、グラフ構造に対してクエリを投げ、周辺の語彙と文脈を照らすことができました。

まとめ

最新のNeo4jをセットアップし、インポートツールを使用してデータの初期ロードを行いました。

特許文書から抽出したキーワード同士の関連と、キーワードが現れる文脈としての分類データのグラフを、あるキーワードを起点として探索しました。

グラフ構造は複雑で、データの量が多くなると全てを把握し見通すことは困難となり、合理的なコストで探索できることがなにより重要になってきます。その点でNeo4jは扱いやすく、一定の規模のデータに対して探索的なクエリ実行ができるので、強力な武器になりそうです。

スマートスピーカー向けに、ブレインストーミングの相手をしてくれるようなアプリケーションを開発してみても面白いかもしれません。

*1:https://neo4j.com

Neo4jをより詳しく知りたい方向けの参考書籍

グラフ型データベース入門 - Neo4jを使う Neo4jユーザーグループ

グラフデータベース ―Neo4jによるグラフデータモデルとグラフデータベース入門 Ian Robinson

O’Reilly’s Graph Databases(無料ダウンロード・英語)

*2:プリエンプティブ仮想マシンを指定することで少し余裕のあるインスタンスをリーズナブルなコストで使用できます

*3:Neo4jの2018年1月23日時点で最新のα版。安定版の最新は3.3.2です

*4:国内の特許公報文書には、案件毎に複数の分類体系のコードが付与され、特許の先行技術調査を行う際に利用されます。Fタームという分類体系もその一つです。

*5:https://neo4j.com/docs/operations-manual/current/installation/linux/

*6:安定版をインストールする場合はリポジトリのtestingをstableにします。

*7:https://neo4j.com/docs/operations-manual/current/tools/import/

*8:http://neo4j.com/docs/developer-manual/current/cypher/clauses/load-csv/

*9:https://neo4j.com/docs/operations-manual/current/tools/import/file-header-format/

*10:以前のバージョンではneo4j-shellというコマンドでした。こちらはまだ存在はしますが、cypher-shellが後継となります

*11:Web UI(デフォルトで7474ポート)にアクセスしてクエリを実行すると、ビジュアライゼーションされたグラフがきれいに表示されます。結果はテーブル形式、テキスト形式、JSONコード形式に切替えられます。また、グラフ表示でノードをダブルクリックすると周辺のノードが展開されます。クエリを投げながら探索の方向性を探るといった使い方ができます。

Copyright © astamuse company, ltd. all rights reserved.