LoginSignup
6
11

More than 5 years have passed since last update.

Elasticquent を使って、LaravelからElasticSearchのデータを取得する

Posted at

Elasticquent を利用して、Laravelで検索画面を作り、
ElasticSearchのAPIを呼び出して、結果を表示する画面を作ります。

※ ElasticSearch側の設定は、こちらをご覧ください。
https://qiita.com/nonoichi123/items/1cf9c5752686c9a14c86

Elasticquentライブラリの場所

上記のページを元に、インストール作業を実行する

  1. composer で ライブラリをインストール
  2. config/app.php に追記
  3. 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)にアクセス

スクリーンショット 2017-10-11 15.42.07.png

検索画面で「talend」と入力して検索した結果

ファイル名、ファイルの中身の一致箇所をハイライト表示、ダウンロードリンクを
表形式で表示

スクリーンショット 2017-10-11 15.42.19.png

ダウンロードボタンをクリックすると、ファイルがダウンロードされる

スクリーンショット 2017-10-11 15.42.42.png

ファイルの中身検索を無償のツールで実現したく、
色々と考えて、ElasticSearchが良さそうだという結論になり、触ってきましたが、
最近、AlfrescoというオープンソースCMSを知りました。

このCMSには、ApacheSolr が搭載されており、
ワークフローやCMS機能など様々な機能が搭載されており、
品質も良いようで、
興味がAlfrescoに移ってきているこの頃です。。

6
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
11