Solrに入門する
文書検索のシステムを導入しようとしており、詳しい人に相談したら、まずはSolr試そうという話でまとまって帰って来た。
今回の要件にSolrはマッチしないだろうな、というなんとなくの両者コンセンサスはあるが、仮にマッチしたら楽で済むし、マッチしないにしても比較対象としてSolrを持っておくのは良い。
とにかく、Solrを一切触ったことがない状態であるのがいまの自分の問題なので、まずは使い始めて試行錯誤できる状態までもっていく。
インストール・起動
まずmacにSolrをインストール。バージョンは7.3.1。
$ brew info solr solr: stable 7.3.1 ...(略)... $ brew install solr $ solr version 7.3.1
Solrのstandalone serverを起動。Javaのバージョンは10を利用。
$ java -version java version "10.0.1" 2018-04-17 Java(TM) SE Runtime Environment 18.3 (build 10.0.1+10) Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10.0.1+10, mixed mode) $ solr start
Solrが起動できたらブラウザでアクセスする。デフォルトでは8983番ポートで起動している。
http://localhost:8983/
※ standalone以外にいくつか構成がとれるらしい。今回はその詳しいところは踏み込まないようにして、一番シンプルなstandaloneにしている。
検索システムだって高可用性にしたい!SolrCloudを用いた高可用性構成の紹介 - Start Today Technologies TECH BLOG
文書の登録
コア?コレクション?
文書を登録するには、まずコアまたはコレクションと呼ばれるものを作らないといけないらしい。
Solrにはコアとコレクションという概念があり、ドキュメント上はこう説明されている。
Collection
In Solr, one or more Documents grouped together in a single logical index using a single configuration and Schema.
In SolrCloud a collection may be divided up into multiple logical shards, which may in turn be distributed across many nodes, or in a Single node Solr installation, a collection may be a single Core.
Core
An individual Solr instance (represents a logical index). Multiple cores can run on a single node. See also SolrCloud.
Solr Glossary | Apache Solr Reference Guide 7.3
なんとなくは分かるが・・・。
stackoverflowに書かれている内容が、なんとなくの今の理解とあってるので、いったん「standalone構成ではcoreとcollectionは同一」と捉えておく。SolrのWeb UI上でも「Add Core」しかなくて「Add Collection」はない。今は深入りしない。
lucene - Solr Collection vs Cores - Stack Overflow
コアの作成
コアを「testcore」という名前で作る。warningが出るが無視。
$ solr create_core -c testcore WARNING: Using _default configset with data driven schema functionality. NOT RECOMMENDED for production use. To turn off: bin/solr config -c testcore -p 8983 -property update.autoCreateFields -value false Created new core 'testcore'
文書の登録
Solrインストール時にサンプルの文書がついてくるので、それを利用する。
$ post -c testcore /usr/local/Cellar/solr/7.3.1/example/exampledocs/*.xml ...(中略)... COMMITting Solr index changes to http://localhost:8983/solr/testcore/update... Time spent: 0:00:00.884
検索
Solr TutorialのBasic Searchingを試す。全ドキュメント(のうちの最初の10件)を取り出している。
http://lucene.apache.org/solr/guide/7_3/solr-tutorial.html#tutorial-searching
$ curl 'http://localhost:8983/solr/testcore/select?q=*:*' { "responseHeader":{ "status":0, "QTime":0, "params":{ "q":"*:*"}}, "response":{"numFound":32,"start":0,"docs":[ { ...(中略)... }}
次いで、Search for a Single Termを試す。クエリの単語が含まれる文書すべてが返却されてくるはず、、、が、レスポンス0件。
http://lucene.apache.org/solr/guide/7_3/solr-tutorial.html#search-for-a-single-term
$ curl 'http://localhost:8983/solr/testcore/select?q=foundation' { "responseHeader":{ "status":0, "QTime":0, "params":{ "q":"foundation"}}, "response":{"numFound":0,"start":0,"docs":[] }}
原因不明のまま、いったんここで打ち止め。
その他
solrコマンドのヘルプを見る。
$ solr Usage: solr COMMAND OPTIONS where COMMAND is one of: start, stop, restart, status, healthcheck, create, create_core, create_collection, delete, version, zk, auth, assert, config Standalone server example (start Solr running in the background on port 8984): ./solr start -p 8984 SolrCloud example (start Solr running in SolrCloud mode using localhost:2181 to connect to Zookeeper, with 1g max heap size and remote Java debug options enabled): ./solr start -c -m 1g -z localhost:2181 -a "-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1044" Pass -help after any COMMAND to see command-specific usage information, such as: ./solr start -help or ./solr stop -help
solrの状態を確認する。
$ solr status Found 1 Solr nodes: Solr process 22634 running on port 8983 { "solr_home":"/usr/local/Cellar/solr/7.3.1/server/solr", "version":"7.3.1 ae0705edb59eaa567fe13ed3a222fdadc7153680 - caomanhdat - 2018-05-09 09:30:57", "startTime":"2018-06-02T06:17:57.876Z", "uptime":"0 days, 0 hours, 7 minutes, 42 seconds", "memory":"59.4 MB (%12.1) of 490.7 MB"}
今後
Search for a Single Termのレスポンス0件問題の解決を試みる。
SolrのチュートリアルはSolrCloud前提で書かれているので、standaloneではなくSolrCloud構成で試してみるか。
あと、登録する文書のフォーマットについても調査する。
Swift: typealiasのスコープ
Type Aliasのスコープってどうなってるんだろうという単純な疑問。
ドキュメントを見ても書いてない(見てるところが違う?)。
The Swift Programming Language (Swift 4.0.3): Declarations
通常の変数と同じスコープ管理されてるだろうという仮説のもと、playgroundで試してみる。
do { typealias ColorCode = UInt8 let r = ColorCode.max print(r) } let g = ColorCode.min print(g)
エラーが出る。
Playground execution failed: error: TypeAlias.playground:5:9: error: use of unresolved identifier 'ColorCode' let g = ColorCode.min ^~~~~~~~~
予想通りの結果となった。
Type Aliasに限らず、Declarationsは同じスコープ管理がされているようだ。
The Swift Programming Language (Swift 4.0.3)をざっと読む限りscope
の定義が見当たらないのだけど、暗黙の共通認識という扱いなのだろうか。
2018年 Rustチャレンジ
2018年に新しく学ぶ言語としてRustにチャレンジしてみる。
Rustのドキュメント(邦訳)を見ながら進める。
http://rust-lang-ja.github.io/the-rust-programming-language-ja/1.6/book/
ドキュメントの本家はこっち。
https://doc.rust-lang.org/book/
環境構築
Rustの開発ツールはHomebrewで簡単にインストールできる。
rustc
やcargo
といったコマンドがインストールされる。
$ brew install rust
新規プロジェクト作成
Cargoを利用してプロジェクトを作成する。
バイナリを作成するため--bin
オプションをつける。
$ cargo new rustlang-intro --bin $ cd rustlang-intro/ $ cargo build $ cargo run Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs Running `target/debug/rustlang-intro` Hello, world!
リリースビルドをするには--release
オプションをつける。
すると、target/release
の下に成果物が作成される。
$ cargo build --release
標準入力
標準入力で受けた文字列を標準エラー出力に表示する。
use std::io; fn print_stdin() { let mut line = String::new(); let _ = io::stdin().read_line(&mut line); eprintln!("{}", line.trim()); }
乱数生成
rand
クレートを利用して乱数を生成・表示する。
まず、Cargo.toml
に依存関係を記述する。
[dependencies] rand = "0.4.1"
10回乱数を生成して表示する。
extern crate rand; fn print_random_numbers() { for _ in 0..10 { let n = rand::random::<i32>(); println!("{}", n) } }
こう書くこともできる。
extern crate rand; use rand::Rng; fn print_random_numbers() { let mut rng = rand::thread_rng(); for _ in 0..10 { let n = rng.gen::<i32>(); println!("{}", n) } }
構造体
構造体を作る。メソッド実装にはimpl
ブロックを利用する。
new
メソッドで構造体初期化を行なっているが、メソッド名は慣習でしかなく、名前はなんでも良い。
また、このようにself
を引数に持たないメソッドは関連関数(associated function)と呼ばれるが、他の言語で言う静的メソッド(static method)に該当するものと思っておけば良い。
struct Person { name: String, } impl Person { fn new(name: &str) -> Person { Person { name: name.to_string(), } } fn get_name(&self) -> &String { &self.name } } fn main() { let p = Person::new("person's name"); println!("{}", p.get_name()); }
ちなみに、以下のようなコードを書いてしまうとエラーになる。
借り物(self
)から勝手に所有権をmoveできないということ。
上のコードのように参照で返すようにしなければコンパイルが通らない。
fn get_name(&self) -> String { self.name }
error[E0507]: cannot move out of borrowed content --> src/main.rs:33:9 | 33 | self.name | ^^^^ cannot move out of borrowed content
トレイト
trait Hello { fn say(&self); } impl Hello for Person { fn say(&self) { println!("Hello {}", self.name); } } fn main() { let h = Person::new("trait"); h.say(); }
マクロ
引数なし版と引数あり版の簡単なものを作ってみる。
macro_rules! say_hello { () => { println!("Hello"); }; ($x:expr) => { println!("Hello {}", $x); }; } fn main() { say_hello!(); say_hello!("name"); }
テスト
テストを書いてみる。
慣習的にテストコードを入れる専用のモジュールを作っておくらしい。cargo test
のときだけコンパイルされる条件付きコンパイルのフラグをつけておく。
fn add(x: i64, y: i64) -> i64 { return x + y; } #[cfg(test)] mod tests { use super::*; #[test] fn test_add() { assert_eq!(10, add(4, 6)); } }
$ cargo test ...(中略)... running 1 test test tests::test_add ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
まとめ
環境構築から基本的な記述まで試すことができた。
借用の概念がまだ自分の中で綺麗に整理できていないのでもう少し資料を漁りながら試してみることにする。
今度はマルチスレッドでHTTPサーバでも実装してみる。