Elasticquent を利用して、Laravelで検索画面を作り、
ElasticSearchのAPIを呼び出して、結果を表示する画面を作ります。
※ ElasticSearch側の設定は、こちらをご覧ください。
https://qiita.com/nonoichi123/items/1cf9c5752686c9a14c86
Elasticquentライブラリの場所
上記のページを元に、インストール作業を実行する
- composer で ライブラリをインストール
- config/app.php に追記
- vendor:publish を行い、config/elasticquent.php を生成
次から、ファイルの編集および作成をしていきます。
config/elasticquent.php
ElasticSearch のポートはデフォルトの9200ポート
インデックス名は、「search_doc」として作成しました。
<?php
return array(
/*
|--------------------------------------------------------------------------
| Custom Elasticsearch Client Configuration
|--------------------------------------------------------------------------
|
| This array will be passed to the Elasticsearch client.
| See configuration options here:
|
| http://www.elasticsearch.org/guide/en/elasticsearch/client/php-api/current/_configuration.html
*/
'config' => [
'hosts' => ['localhost:9200'],
'retries' => 1,
],
/*
|--------------------------------------------------------------------------
| Default Index Name
|--------------------------------------------------------------------------
|
| This is the index name that Elasticquent will use for all
| Elasticquent models.
*/
'default_index' => 'search_doc',
);
app/Http/Controllers/SearchController.php
※SearchController.phpファイル 作成は、Artisanコマンドで作成
php artisan make:controller SearchController
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Document;
class SearchController extends Controller
{
public function __construct()
{
}
public function index()
{
return view('search');
}
public function result(Request $request)
{
$input = $request->all();
//$ret = \App\Document::search($input['q']);
$ret = \App\Document::complexSearch([
'body' => [
'size' => 100,
'query' => [
'match' => [
'file.content' => $input['q']
]
],
'highlight' => [
'pre_tags' => '<em style="color:#cc0000;">',
'post_tags' => '</em>',
'fields' => [
'file.content' => new \stdClass()
]
]
]
]);
$ret = $ret->getHits();
return view('search_result', ['ret' => $ret, 'q' => $input['q']]);
}
public function download($id)
{
$ret = \App\Document::complexSearch([
'body' => [
'query' => [
'match' => [
'_id' => $id
]
]
]
]);
$ret = $ret->getHits();
$tmpdir = '../storage/tmp/';
$data = base64_decode($ret['hits'][0]['_source']['file']);
file_put_contents($tmpdir.$ret['hits'][0]['_source']['title'], $data);
return response()->download($tmpdir.$ret['hits'][0]['_source']['title']);
}
}
Document.php
App 配下に、Document.phpファイルを作成し、以下を記載
※Document.phpファイル 作成は、Artisanコマンドで作成
php artisan make:model Document
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Elasticquent\ElasticquentTrait;
class Document extends Model
{
use ElasticquentTrait;
}
routes/web.php
routes/web.php に以下を追記
Route::get('/search', 'SearchController@index')->name('search');
Route::get('/search/result/download/{id}', 'SearchController@download')->name('search_result_download');
Route::get('/search/result', 'SearchController@result')->name('search_result');
views/search.blade.php
検索画面と検索結果画面の2テンプレートを作成
<form action="/search/result" method="get">
{!! csrf_field() !!}
<div class="form-group has-feedback {{ $errors->has('keyword') ? 'has-error' : '' }}">
</div>
<div class="form-group has-feedback {{ $errors->has('q') ? 'has-error' : '' }}">
<input type="text" name="q" class="form-control" value="{{ old('q') }}"
placeholder="{{ trans('please input keyword...') }}">
<span class="glyphicon form-control-feedback fa fa-search"></span>
@if ($errors->has('keyword'))
<span class="help-block">
<strong>{{ $errors->first('keyword') }}</strong>
</span>
@endif
</div>
<button type="submit"
class="btn btn-primary btn-block btn-flat">
{{ trans('search') }}</button>
</form>
views/search_result.blade.php
<section class="content">
<div class="row">
<div class="col-xs-12">
<div class="box">
<div class="box-header">
<h3 class="box-title">Search Result</h3>
<div class="box-tools">
<form action="/search/result" method="get">
<div class="input-group input-group-sm" style="width: 150px;">
<input type="text" name="q" class="form-control" value="{{ $q }}"
placeholder="{{ trans('search...') }}">
<div class="input-group-btn">
<button type="submit" class="btn btn-default"><i class="fa fa-search"></i></button>
</div>
</div>
</form>
</div>
</div>
<!-- /.box-header -->
<div class="box-body table-responsive no-padding">
<table class="table table-hover">
<tbody><tr>
<!--th>Thumbnail Image</th>-->
<th>Title</th>
<!--<th>Date</th>
<th>ContentType</th>-->
<th>Highlight</th>
<th>Download</th>
</tr>
@foreach($ret['hits'] as $r)
<tr>
<!--<td>
<a href="https://themequarry.com/theme/ample-admin-the-ultimate-dashboard-template-ASFEDA95" class="ad-click-event">
<img src="https://themequarry.com/storage/images/approved/ASFEDA95_v1.0_58db8909df34d.png" alt="Ample Admin" class="media-object" style="width: 150px;height: auto;border-radius: 4px;box-shadow: 0 1px 3px rgba(0,0,0,.15);">
</a>
</td>-->
<td>{{ $r['_source']['title'] }}</td>
<!--<td>11-7-2014</td>
<td><span class="label label-success">Approved</span></td>-->
<td>{!! nl2br($r['highlight']['file.content'][0]) !!}</td>
<td><a href="/search/result/download/{{ ($r['_id']) }}">Download</a></td>
</tr>
@endforeach
</tbody></table>
</div>
<!-- /.box-body -->
</div>
<!-- /.box -->
</div>
</div>
</section>
表示確認
こんな感じでファイルを作ると、
以下の感じで動作しました。
検索画面(/search)にアクセス
検索画面で「talend」と入力して検索した結果
ファイル名、ファイルの中身の一致箇所をハイライト表示、ダウンロードリンクを
表形式で表示
ダウンロードボタンをクリックすると、ファイルがダウンロードされる
ファイルの中身検索を無償のツールで実現したく、
色々と考えて、ElasticSearchが良さそうだという結論になり、触ってきましたが、
最近、AlfrescoというオープンソースCMSを知りました。
このCMSには、ApacheSolr が搭載されており、
ワークフローやCMS機能など様々な機能が搭載されており、
品質も良いようで、
興味がAlfrescoに移ってきているこの頃です。。