ACM-ICPC 2017 国内予選に参加した話

7/14(金)15:00ぐらいから席についてプリンターの用意をし始めて,コーラを買ってきてスタンバイ. 一緒に出たのは同じ研究室のPくんとSくん.

16:30に開始した

問題解き解きタイム

とりあえず僕とSくんでB問題に目を通す. B問題ざっくりと考察していた.とりあえず完全一致見るよねぇーとか言っていた. その間にPくん,A問題AC.

速い

その後SくんがPくんにB問題の内容を教えている間に僕がC問題を読む. C問題読んでどうしよっかな〜って考えていたら,Sくんが帰還して一緒に考える. とりあえず全探索しとこうという話になる.Pくんにぶん投げ.

D問題をとりあえず読んで見る.DPかなぁって思いつつ考察していたが,やり方いまいちわかっておらずPくんにそのままぶん投げた.

後はひたすら読める問題から読みまくっていた.D問題よりG問題の方が簡単じゃね?って思いつつ読んでいて,Pくんに投げたかったが時間切れ.

結果は3完75位でした.

まとめ

Pくんにぶん投げすぎ.

Play FrameworkでJSONを触ってみる

POSTリクエストとしてJsonを受け取り,そのJsonをencodeしたりdecodeしたりしてみた

conf/routesを変更

POST    /json                       controllers.JSONController.jsonParse 

コントローラーの記述

package controllers

import javax.inject.Inject

import play.api.mvc.{Action, Controller}

import play.api.libs.json._

// caseクラスを定義
case class Person(username: String, password: String)
// コンパニオンオブジェクトを定義
object Person {
  implicit def jsonWrites = Json.writes[Person]
  implicit def jsonReads = Json.reads[Person]
}

/**
  * Created by mituba on 2017/06/30.
  */
class JSONController @Inject() extends Controller {
  def jsonParse = Action { request =>
    // getRequestJson
    val params : Option[JsValue] = request.body.asJson
    val json = params.get

    // encode
    val result: JsResult[Person] = json.validate[Person]
    val person: Person = result.get
    println(person.username + " " + person.password)

    // decode
    val decodeJson: JsValue = Json.toJson(person)
    println(decodeJson.toString())

    Ok(decodeJson.toString())
  }
}

curlでPOSTする

curl -H "Content-Type: application/json" -X POST -d '{"username":"xyz","password":"xyz"}' http://localhost:9000/json

無事Jsonを受け取って,encode,decodeできました.

参考

以下のサイトを参考にしてもらいました.

qiita.com

play frameworkを使ってみる

activatorをインストー

brew install typesafe-activator 

プロジェクトの作成

activator new myapp play-scala 

myappというディレクトリができました.

myappに移動して,sbt compileコンパイルsbt runで実行します.

http://localhost:9000/にアクセスすると,play frameworkの画面がでてきました.

とりあえずプロジェクト作成時に出てきたソースコードを見てみる.

conf/routes

# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~

# An example controller showing a sample home page
GET     /                           controllers.HomeController.index
# An example controller showing how to use dependency injection
GET     /count                      controllers.CountController.count
# An example controller showing how to write asynchronous code
GET     /message                    controllers.AsyncController.message

# Map static resources from the /public folder to the /assets URL path
GET     /assets/*file               controllers.Assets.versioned(path="/public", file: Asset)

requestMapping的な何かをしてそうなところ

HomeControllerを見てみる

package controllers

import javax.inject._
import play.api._
import play.api.mvc._

/**
 * This controller creates an `Action` to handle HTTP requests to the
 * application's home page.
 */
@Singleton
class HomeController @Inject() extends Controller {

  /**
   * Create an Action to render an HTML page with a welcome message.
   * The configuration in the `routes` file means that this method
   * will be called when the application receives a `GET` request with
   * a path of `/`.
   */
  def index = Action {
    Ok(views.html.index("Your new application is ready."))
  }
}

views/index.scala.htmlを返してそう

index.scala.htmlは同じところにあるmain.scala.htmlを読んでいるらしい

CountControllerを見てみる

package controllers

import javax.inject._
import play.api._
import play.api.mvc._

import services.Counter

/**
 * This controller demonstrates how to use dependency injection to
 * bind a component into a controller class. The class creates an
 * `Action` that shows an incrementing count to users. The [[Counter]]
 * object is injected by the Guice dependency injection system.
 */
@Singleton
class CountController @Inject() (counter: Counter) extends Controller {

  /**
   * Create an action that responds with the [[Counter]]'s current
   * count. The result is plain text. This `Action` is mapped to
   * `GET /count` requests by an entry in the `routes` config file.
   */
  def count = Action { Ok(counter.nextCount().toString) }

}

counter.nextCount()を呼んでそう

counterクラスを呼んでそう

Counter.scalaを見てみる

package services

import java.util.concurrent.atomic.AtomicInteger
import javax.inject._

/**
 * This trait demonstrates how to create a component that is injected
 * into a controller. The trait represents a counter that returns a
 * incremented number each time it is called.
 */
trait Counter {
  def nextCount(): Int
}

/**
 * This class is a concrete implementation of the [[Counter]] trait.
 * It is configured for Guice dependency injection in the [[Module]]
 * class.
 *
 * This class has a `Singleton` annotation because we need to make
 * sure we only use one counter per application. Without this
 * annotation we would get a new instance every time a [[Counter]] is
 * injected.
 */
@Singleton
class AtomicCounter extends Counter {  
  private val atomicCounter = new AtomicInteger()
  override def nextCount(): Int = atomicCounter.getAndIncrement()
}

トレイトを実装したAtomicCounterがあった

getAndIncrement()で1足した値を取得してるっぽい

返ってきたやつをtoStringして出力といった感じ

とりあえずコントローラーにメソッドを一つ追加してみる

conf/routesを変更

GET     /test                       controllers.TestController.test

TestControllerの追加

package controllers

import javax.inject.Inject

import play.api.mvc.{Action, Controller}

/**
  * Created by mituba on 2017/06/29.
  */
class TestController @Inject() extends Controller {
  def test = Action {
    Ok("hello")
  }
}

実行してhttp://localhost:9000/testにアクセスするとhelloという文字が出た

とりあえずリクエストパラメータをもらってみる

conf/routesの変更

GET     /params                     controllers.ParamController.getParam

ParamController.scalaの追加

package controllers

import javax.inject.Inject

import play.api.mvc.{Action, Controller}


/**
  * Created by mituba on 2017/06/29.
  */
class ParamController @Inject() extends Controller  {
  def getParam = Action { request =>
    val params : Map[String, Seq[String]] = request.queryString
    val message = params("message").head

    Ok(message)
  }
}

実行してhttp://localhost:9000/params?message=helloにアクセスすると,helloと表示された.

まとめ

後はJSONの送り合いとDB処理の実装について調べてみたい.

Apache Solrを利用してみた

この記事はApache Solrの設定からpythonによる使用までを書いていく記事です。 今回Apache Solrのバージョンは、5.5.0を対象にします。

参考

ダウンロード

リンクからバージョンを選んでダウンロードして下さい。(解凍も忘れずに)

解凍後のディレクトリに移動して、作業していきます。

サーバ起動

Apache Solrの起動は以下のコマンドで行います.

bin/solr start

以下のリンクに飛ぶと、Apache Solrという画面が出てくると思います。

これで起動成功です。

起動時のポート番号を指定する場合

bin/solr start -p $(port_number)

コア

コアとは、一つのデータベースみたいなものです。 コアごとにいろいろデータを登録していきます。

  • 作成
bin/solr create -c $(core_name)
  • 削除
bin/sor delete -c $(core_name)

ドキュメント登録

bin/post -c $(core_name) $(file_name)

対応ファイルは、

検索

ここから登録したドキュメントに対して検索を行います. 以下のコードをコピペして,main.pyというファイルを作成してください. (core_nameとqueryを各自のコア名と検索単語に変えてください)

import urllib

url = "http://localhost:8983/solr/<core_name>/select?q=<query>&wt=python&indent=true"
res = urllib.urlopen(url) # urlを開く
response = eval(res.read()) # dictを取り出す

# 検索結果のdictを、hitとして取り出す
for hit in response['response']['docs']:
    # hitを用いた処理を書く(ex. hit['data'] -> dataという名前のkeyのValueを取得する)

いろいろなパラメータ

Apache Solrは多くのパラメータによって検索結果を変更することができます. 以下に今回使用するパラメータを示します.

パラメータ 役割
sort 与えられた値でソートをする(ex. &sort=<field_name>)        
rows 取得件数を設定する(ex. &rows=100)            
fl 検索結果として取ってくるフィールドを設定する(ex. &fl=<field_name>)

パラメータを用いた検索

url = "http://localhost:8983/solr/<core_name>/select?q=<query>&sort=strdist(<fl_name>,<query>,edit)+desc&rows=100&fl=<fl_name>&wt=python&indent=true"

ファンクションクエリ(strdist関数)

上記のパラメータを用いた検索で利用したstrdistなどはファンクションクエリといいます.strdistの他に多数あります.

strdist(<str1>, <str2>, edit)

この場合はstr1とstr2の距離をはかって、値を返します。 他にもいろいろありますが、使用してないので説明は省きます。

ファンクションクエリを使う際の注意点

Apache Solrの性質上、登録したドキュメントを用いてソートなどを利用したい時には設定を変えないとエラーになります.

そこで回避方法としてsolr-x.x.x/server/solr/<core_name>/conf/managed-schemaの中を少し変更します。

  • 変更内容
multiValued="true"
↓
multiValued="false"

その後、以下のコマンドで再起動し修正完了です。

bin/solr restart

まとめ

起動→コア作成→データ登録→検索、までが一連の流れです。