GithubHelp home page GithubHelp logo

elasticquent / elasticquent Goto Github PK

View Code? Open in Web Editor NEW
1.3K 1.3K 403.0 140 KB

Maps Laravel Eloquent models to Elasticsearch types

License: MIT License

PHP 100.00%
elasticsearch eloquent eloquent-models laravel

elasticquent's Introduction

Elasticquent

Elasticsearch for Eloquent Laravel Models

Elasticquent makes working with Elasticsearch and Eloquent models easier by mapping them to Elasticsearch types. You can use the default settings or define how Elasticsearch should index and search your Eloquent models right in the model.

Elasticquent uses the official Elasticsearch PHP API. To get started, you should have a basic knowledge of how Elasticsearch works (indexes, types, mappings, etc).

Elasticsearch Requirements

You must be running at least Elasticsearch 1.0. Elasticsearch 0.9 and below will not work and are not supported.

Contents

Reporting Issues

If you do find an issue, please feel free to report it with GitHub's bug tracker for this project.

Alternatively, fork the project and make a pull request :)

Overview

Elasticquent allows you take an Eloquent model and easily index and search its contents in Elasticsearch.

    $books = Book::where('id', '<', 200)->get();
    $books->addToIndex();

When you search, instead of getting a plain array of search results, you instead get an Eloquent collection with some special Elasticsearch functionality.

    $books = Book::search('Moby Dick');
    echo $books->totalHits();

Plus, you can still use all the Eloquent collection functionality:

    $books = $books->filter(function ($book) {
        return $book->hasISBN();
    });

Check out the rest of the documentation for how to get started using Elasticsearch and Elasticquent!

How Elasticquent Works

When using a database, Eloquent models are populated from data read from a database table. With Elasticquent, models are populated by data indexed in Elasticsearch. The whole idea behind using Elasticsearch for search is that its fast and light, so you model functionality will be dictated by what data has been indexed for your document.

Setup

Before you start using Elasticquent, make sure you've installed Elasticsearch.

To get started, add Elasticquent to you composer.json file:

"elasticquent/elasticquent": "dev-master"

Once you've run a composer update, you need to register Laravel service provider, in your config/app.php:

'providers' => [
    ...
    Elasticquent\ElasticquentServiceProvider::class,
],

We also provide a facade for elasticsearch-php client (which has connected using our settings), add following to your config/app.php if you need so.

'aliases' => [
    ...
    'Es' => Elasticquent\ElasticquentElasticsearchFacade::class,
],

Then add the Elasticquent trait to any Eloquent model that you want to be able to index in Elasticsearch:

use Elasticquent\ElasticquentTrait;

class Book extends Eloquent
{
    use ElasticquentTrait;
}

Now your Eloquent model has some extra methods that make it easier to index your model's data using Elasticsearch.

Elasticsearch Configuration

By default, Elasticquent will connect to localhost:9200 and use default as index name, you can change this and the other settings in the configuration file. You can add the elasticquent.php config file at /app/config/elasticquent.php for Laravel 4, or use the following Artisan command to publish the configuration file into your config directory for Laravel 5:

$ php artisan vendor:publish --provider="Elasticquent\ElasticquentServiceProvider"
<?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 Elastiquent will use for all
    | Elastiquent models.
    */

    'default_index' => 'my_custom_index_name',

);

Indexes and Mapping

While you can definitely build your indexes and mapping through the Elasticsearch API, you can also use some helper methods to build indexes and types right from your models.

If you want a simple way to create indexes, Elasticquent models have a function for that:

Book::createIndex($shards = null, $replicas = null);

For custom analyzer, you can set an indexSettings property in your model and define the analyzers from there:

    /**
     * The elasticsearch settings.
     *
     * @var array
     */
    protected $indexSettings = [
        'analysis' => [
            'char_filter' => [
                'replace' => [
                    'type' => 'mapping',
                    'mappings' => [
                        '&=> and '
                    ],
                ],
            ],
            'filter' => [
                'word_delimiter' => [
                    'type' => 'word_delimiter',
                    'split_on_numerics' => false,
                    'split_on_case_change' => true,
                    'generate_word_parts' => true,
                    'generate_number_parts' => true,
                    'catenate_all' => true,
                    'preserve_original' => true,
                    'catenate_numbers' => true,
                ]
            ],
            'analyzer' => [
                'default' => [
                    'type' => 'custom',
                    'char_filter' => [
                        'html_strip',
                        'replace',
                    ],
                    'tokenizer' => 'whitespace',
                    'filter' => [
                        'lowercase',
                        'word_delimiter',
                    ],
                ],
            ],
        ],
    ];

For mapping, you can set a mappingProperties property in your model and use some mapping functions from there:

protected $mappingProperties = array(
   'title' => array(
        'type' => 'string',
        'analyzer' => 'standard'
    )
);

If you'd like to setup a model's type mapping based on your mapping properties, you can use:

    Book::putMapping($ignoreConflicts = true);

To delete a mapping:

    Book::deleteMapping();

To rebuild (delete and re-add, useful when you make important changes to your mapping) a mapping:

    Book::rebuildMapping();

You can also get the type mapping and check if it exists.

    Book::mappingExists();
    Book::getMapping();

Setting a Custom Index Name

By default, Elasticquent will look for the default_index key within your configuration file(config/elasticquent.php). To set the default value for an index being used, you can edit this file and set the default_index key:

return array(

   // Other configuration keys ...
   
   /*
    |--------------------------------------------------------------------------
    | Default Index Name
    |--------------------------------------------------------------------------
    |
    | This is the index name that Elastiquent will use for all
    | Elastiquent models.
    */
    
   'default_index' => 'my_custom_index_name',
);

If you'd like to have a more dynamic index, you can also override the default configuration with a getIndexName method inside your Eloquent model:

function getIndexName()
{
    return 'custom_index_name';
}

Note: If no index was specified, Elasticquent will use a hardcoded string with the value of default.

Setting a Custom Type Name

By default, Elasticquent will use the table name of your models as the type name for indexing. If you'd like to override it, you can with the getTypeName function.

function getTypeName()
{
    return 'custom_type_name';
}

To check if the type for the Elasticquent model exists yet, use typeExists:

    $typeExists = Book::typeExists();

Indexing Documents

To index all the entries in an Eloquent model, use addAllToIndex:

    Book::addAllToIndex();

You can also index a collection of models:

    $books = Book::where('id', '<', 200)->get();
    $books->addToIndex();

You can index individual entries as well:

    $book = Book::find($id);
    $book->addToIndex();

You can also reindex an entire model:

    Book::reindex();

Searching

There are three ways to search in Elasticquent. All three methods return a search collection.

Simple term search

The first method is a simple term search that searches all fields.

    $books = Book::search('Moby Dick');

Query Based Search

The second is a query based search for more complex searching needs:

    public static function searchByQuery($query = null, $aggregations = null, $sourceFields = null, $limit = null, $offset = null, $sort = null)

Example:

    $books = Book::searchByQuery(array('match' => array('title' => 'Moby Dick')));

Here's the list of available parameters:

  • query - Your ElasticSearch Query
  • aggregations - The Aggregations you wish to return. See Aggregations for details.
  • sourceFields - Limits returned set to the selected fields only
  • limit - Number of records to return
  • offset - Sets the record offset (use for paging results)
  • sort - Your sort query

Raw queries

The final method is a raw query that will be sent to Elasticsearch. This method will provide you with the most flexibility when searching for records inside Elasticsearch:

    $books = Book::complexSearch(array(
        'body' => array(
            'query' => array(
                'match' => array(
                    'title' => 'Moby Dick'
                )
            )
        )
    ));

This is the equivalent to:

    $books = Book::searchByQuery(array('match' => array('title' => 'Moby Dick')));

Search Collections

When you search on an Elasticquent model, you get a search collection with some special functions.

You can get total hits:

    $books->totalHits();

Access the shards array:

    $books->shards();

Access the max score:

    $books->maxScore();

Access the timed out boolean property:

    $books->timedOut();

And access the took property:

    $books->took();

And access search aggregations - See Aggregations for details:

    $books->getAggregations();

Search Collection Documents

Items in a search result collection will have some extra data that comes from Elasticsearch. You can always check and see if a model is a document or not by using the isDocument function:

    $book->isDocument();

You can check the document score that Elasticsearch assigned to this document with:

    $book->documentScore();

Chunking results from Elastiquent

Similar to Illuminate\Support\Collection, the chunk method breaks the Elasticquent collection into multiple, smaller collections of a given size:

    $all_books = Book::searchByQuery(array('match' => array('title' => 'Moby Dick')));
    $books = $all_books->chunk(10);

Using the Search Collection Outside of Elasticquent

If you're dealing with raw search data from outside of Elasticquent, you can use the Elasticquent search results collection to turn that data into a collection.

$client = new \Elasticsearch\Client();

$params = array(
    'index' => 'default',
    'type'  => 'books'
);

$params['body']['query']['match']['title'] = 'Moby Dick';

$collection = Book::hydrateElasticsearchResult($client->search($params));

More Options

Document IDs

Elasticquent will use whatever is set as the primaryKey for your Eloquent models as the id for your Elasticsearch documents.

Document Data

By default, Elasticquent will use the entire attribute array for your Elasticsearch documents. However, if you want to customize how your search documents are structured, you can set a getIndexDocumentData function that returns you own custom document array.

function getIndexDocumentData()
{
    return array(
        'id'      => $this->id,
        'title'   => $this->title,
        'custom'  => 'variable'
    );
}

Be careful with this, as Elasticquent reads the document source into the Eloquent model attributes when creating a search result collection, so make sure you are indexing enough data for your the model functionality you want to use.

Using Elasticquent With Custom Collections

If you are using a custom collection with your Eloquent models, you just need to add the ElasticquentCollectionTrait to your collection so you can use addToIndex.

class MyCollection extends \Illuminate\Database\Eloquent\Collection
{
    use ElasticquentCollectionTrait;
}

Roadmap

Elasticquent currently needs:

  • Tests that mock ES API calls.
  • Support for routes

elasticquent's People

Contributors

adamfairholm avatar cambricorp avatar chuangbo avatar coffeeburrito avatar corazzi avatar criebs-cmdagency avatar dschniepp avatar gpenverne avatar grahamcampbell avatar k1ng440 avatar linkthrow avatar nwidart avatar onbjerg avatar pauliusmacernis avatar petercoles avatar pwoo avatar romulowspp avatar shekarsiri avatar specialtactics avatar stevenay avatar swhammack avatar thedigit avatar tiagomaial avatar timgws avatar xian13 avatar yswery avatar zakhenry avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

elasticquent's Issues

Hydrating models from results

Hi!

Is it possible to retrieve a collection of models with all of the database info, as opposed to just the documents returned by ElasticSearch?

If not, maybe we could add a hydrate method to the results collection?

Yesterdays merge created this error for me.

Everything was working fine before this morning.

This commit:
b53834f

Error:
Missing argument 1 for Illuminate\Database\Eloquent\Model::updated(), called in /vendor/elasticquent/elasticquent/src/ElasticquentTrait.php on line 693 and defined

Little more data:

  • DB : (Mongo) using "jenssegers/mongodb": "3.0.*" plugin
  • Elasticquent Version : "elasticquent/elasticquent": "dev-master"
  • Laravel Version : "laravel/framework": "5.2.*"

I will see if i can modify the commit to work for my set up and commit my changes for a possible fix. for production I will just going to revert the commit on my side for now to get the app back up but i thought i should share for future development.

Edit: So I believe i have figured out the issue i am having. jenssegers/mongodb puts a modifier on the model obj. which changes the "updated_at" "created_at" to mongo date type obj.

Autocomplete query

I was wondering is there a way in whch i can use an autocomplete mapping, please excuse my dumbness but any takers on a fix?

Class not found

Hello,

I've recently made a clean installation of Lavarel 5.2.31 to try Elasticquent. No problem was notified during the installation process both framework and elastic, and subsequent update. Then, as the tutorial says, I added the respectives entries into providers and aliases:

Providers:
Elasticquent\ElasticquentServiceProvider::class,

Aliases
'Es' => Elasticquent\ElasticquentElasticsearchFacade::class,

Updated composer.json again and it doesn't recognise Elasticquent\ElasticquentServiceProvider::class.

ยฟAny ideas?

Edit: I've also installed Laracasts/Flash and Mcamara/Laravel-Localization. Both run prefectly

Add CI

We only have a static code analyser. We should probably set up Travis CI or similar.

Still Laravel 4 compatible?

I'm in the need of extending an existing L4 app, and tried to follow the setup procedure, but as soon as I copy the "providers" declaration, I get a:

Call to undefined method Elasticquent\ElasticquentServiceProvider::publishes()

pointing to

 public function boot()
    {
        $this->publishes([
            __DIR__.'/config/elasticquent.php' => config_path('elasticquent.php'),
        ]);

I have an /app/config/elasticquent.php file in place, but that doesn't seem to make any difference.

Is this a L5-only-app problem? Any specific branch I can target to get L4 support?

Thanks in advance!

Multiple Mapping on a Fresh Index?

Hi guys, I just want to share this issue I'm having. In case you have an idea.

When I fetch the mappings, it shows me 2 mapping result.

  • default
  • MYINDEX

I tried deleting the whole index too, but everytime I do a Post::rebuildMapping(); it shows me the same result with two mappings.

In my local server, it just shows 1 mapping (no default in it).
But on my live server, it shows 2 mappings.

Am I doing something wrong?
How can I remove that default index in it?

Thanks in advance.

Response:

curl -XGET 'http://localhost:9200/_all/_mapping/posts'
"default": {
    "mappings": {
        "posts": {
            "properties": {
                "address": {
                    "type": "string"
                },
                "contact_no": {
                    "type": "string"
                },
                "created_at": {
                    "type": "string"
                },
                "description": {
                    "type": "string"
                },
                "id": {
                    "type": "long"
                },
                "latitude": {
                    "type": "double"
                },
                "longitude": {
                    "type": "double"
                },
                "title": {
                    "type": "string"
                },
                "updated_at": {
                    "type": "string"
                },
                "user_id": {
                    "type": "long"
                },
                "website": {
                    "type": "string"
                }
            }
        }
    }
},
"MYINDEX": {
    "mappings": {
        "posts": {
            "properties": {
                "address": {
                    "type": "string"
                },
                "contact_no": {
                    "type": "string"
                },
                "created_at": {
                    "type": "date",
                    "format": "yyyy-MM-dd H:m:s"
                },
                "description": {
                    "type": "string"
                },
                "id": {
                    "type": "long"
                },
                "latitude": {
                    "type": "string"
                },
                "longitude": {
                    "type": "string"
                },
                "slug": {
                    "type": "string"
                },
                "title": {
                    "type": "string"
                },
                "type": {
                    "type": "string"
                },
                "updated_at": {
                    "type": "date",
                    "format": "yyyy-MM-dd H:m:s"
                },
                "user_id": {
                    "type": "string"
                },
                "website": {
                    "type": "string"
                }
            }
        }
    }
}

Ability to remove all documents in type

some gurus suggest to delete INDEX, but this is not proper solution cause same INDEX has many TYPEs which have documents.
so we need

  • a function to empty TYPE.
  • a function to delete by query.

How to put index settings such as analyzer when creating index or add meta-fields when put mapping?

Hi @timgws,

I have a difficulty when i want to put custom analyzer when creating index, or adding meta-fields like _all when put mapping.

Can I make modification to the createIndex and putMapping, before the default parameters is sent to the create / putMapping, we can sent it to getCreateIndexParameters and getMappingParameters, so we can easily override that if we want to.

    public static function createIndex($shards = null, $replicas = null)
    {
        $instance = new static;

        $client = $instance->getElasticSearchClient();

        $index = array(
            'index' => $instance->getIndexName(),
        );

        if (!is_null($shards)) {
            $index['body']['settings']['number_of_shards'] = $shards;
        }

        if (!is_null($replicas)) {
            $index['body']['settings']['number_of_replicas'] = $replicas;
        }

        return $client->indices()->create($this->getCreateIndexParameters($index));
    }

    public function getCreateIndexParameters(array $defaultParameters)
    {
        return $defaultParameters;
    }
    public static function putMapping($ignoreConflicts = false)
    {
        $instance = new static;

        $mapping = $instance->getBasicEsParams();

        $params = array(
            '_source' => array('enabled' => true),
            'properties' => $instance->getMappingProperties(),
        );

        $mapping['body'][$instance->getTypeName()] = $params;

        return $instance->getElasticSearchClient()->indices()->putMapping($this->getMappingParameters($mapping));
    }

    public function getMappingParameters(array $defaultParameters)
    {
        return $defaultParameters;
    }

And also I want to add some function for checking and index exists or not (just like typeExists) and recreateIndex (check index exists or not, if exists and forced, delete the index and create it, if not exists just create it).

If you agree, i will create PR for this.

Thank you.

pluck('id') doesn't work

Model gives me fine collection results

$this->subcategory->search('query');

But when I use pluck on it, it throws me this error, am I missing anything here?

$this->subcategory->search('query')->pluck('id');
ErrorException in ElasticquentResultCollection.php line 22:
Missing argument 2 for Elasticquent\ElasticquentResultCollection::__construct(), called in /usr/share/nginx/zapstore/vendor/laravel/framework/src/Illuminate/Support/Collection.php on line 444 and defined

Field [_id] is a metadata field and cannot be added inside a document. Use the index API request parameters.

Hi,
I tried a bulk add as shown is your readme but instead I get this error:

"error" => array:2 [ "type" => "mapper_parsing_exception" "reason" => "Field [_id] is a metadata field and cannot be added inside a document. Use the index API request parameters." ]

The model I'm trying to add is just a test model, and it's something like:

"title" => "MRdTvVwMTGSl" "updated_at" => "2016-04-04 15:58:29" "created_at" => "2016-04-04 15:58:29" "_id" => "57028f25633db3473d0041c8"

I have ElasticSearch 2.1 and it's under Mac OSX 10.11.3
Any advice?

Failed to access when host url with username:password

I am using facetflow.io, a hosted elasticsearch.
Their url have an API KEY prepend to the cluster url, such as:

https://apikey:@example.azure.facetflow.io

When I put in this URL to the config.hosts, facetflow returned error 401, authentication failed.

No problem when I was using aws elasticsearch, as they doesn't prepend any credential to the url.

So I wonder is this a problem with elasticquent or there are some problem with my server?

regards,

Laravel 5.2 paginate

Hello everyone,

I'm new to Laravel and elastic search. Nowadays dealing with paginate function.
Let's say, we're trying to get books with hard cover.

$books = Book::searchByQuery(array('match' => array('cover' => 'hard')))->paginate(12);

In the first page, the code looks like it's working. Laravel paginator works in view, there're results that I'm looking for.

But when I check the results, there's a problem with result count. I asked 12 results per page. As you can see, it returned 10 results which is default value for size parameter, right?

firstpage

The most important problem starts when you try to reach other pages (e.g. /?page=2). Although you can see the pagination links on the view, the collection is empty.

fourthpage

As i mentioned earlier, i'm new to this technologies but imho paginate function must set from and size parameters before making a request to elastic search server.

Am I missing something? Could you please enlighten me about the current pagination process?

Thanks,

reindex

I'm a newbie both with elasticsearch and laravel so it's possible that I'm getting this wrong:
When reindexing, it deletes the items that I have NOW in my source table, and then add them again, so if I deleted an item, it's not deleted from elasticsearch. Shouldn't reindex remove the non existent items?

[Proposal] Restore collection recursive for all the eager load relations

If we index a model with eager loaded relations, search results collection will not restore the relations properly

For example:

// 0. Define Model
class User extends Model
{
    use ElasticquentTrait;

    public function group()
    {
        return $this->belongsTo('App\Group');
    }

    public function isAdmin()
    {
        return $this->group->type == "admin";
    }
}

// 1. Create Index
User::with('group')->addToIndex();
// 2. Search
$user = User::search("name")->first();
dump($user->group);
dump($this->isAdmin());

Expected

App\Group {#739
    id: 4,
    type: "admin"
}
true

But we got

array:2 [
  "id" => 4
  "type" => "admin"
]
PHP error:  Trying to get property of non-object

I noticed it's because ElasticquentResultCollection will only restore _source into raw attributes, includes relations, will be restore as array. Which will break many existing code, like the example above.

So it'd be great if we can restore the whole _source tree recursive properly, ElasticquentResultCollection can restore the exactly data that we add into elasticsearch index.

Similar proposal #46.

Can not use map on ElasticquentResultCollection

This code will not work:

$books = Book::search('moby dick');
$titles = $books->map(function ($book) {
    return $book->title;
});

This is the error that is thrown:

PHP warning:  Missing argument 2 for Elasticquent\ElasticquentResultCollection::__construct(), called in /app/bootstrap/cache/compiled.php on line 12523 and defined in /app/vendor/elasticquent/elasticquent/src/ElasticquentResultCollection.php on line 22

No alive nodes found in your cluster

Weird error when using aws elasticsearch

i know aws works because i can use it fine with postman
'config' => [ 'hosts' => ['aws_endpoint'], 'retries' => 1, ],

Add fuzzyness?

Hello,

what would be the best way to search with some fuzzyness in mind?
Because now, for example I have: "Blackman" - If i search of it, it find. But if I search for "Blackma" (ommiting last letter) - I won't be able to find it and elastic returns - 0 Hits.

Thank you

Enable the use of Elasticquent without underlying SQL DB data.

Hi there,

I'm trying to use Elasticsearch as a NoSQL database and the only database for my application. I thought I could use Elasticquent for that, but there's no way of using Elasticquent in stand-alone mode so to speak, without the models being backed up by actual SQL data. Is there any chance you are going to allow that in the future ?

Right now I'm writing custom methods to go around that, but I think it would be pretty simple to enable this by just disabling some checks. For example in addToIndex, take out the exists check or combine it with another condition:

 public function addToIndex()
    {
        if (!$this->exists) {
            throw new Exception('Document does not exist.');
        }

Is it possible to track every actions of user as a document?

For example in my case user with id 100 update the record with id 12 and then another user or may be the same user update this record, am i able to store both of them not update the stored document.
please help me how can i do that? thanks.

problem mappingProperties

Hi, I have just started using this package and I am getting:

Fatal error: App\Part and Elasticquent\ElasticquentTrait define the same property ($mappingProperties) in the composition of App\Part. However, the definition differs and is considered incompatible. Class was composed in /var/www/html/testProject/app/Part.php on line 27

 protected $mappingProperties = array(
        'PART_NO' => [
            'type' => 'string',
            "analyzer" => "standard",
        ],
        'DESCRIPTION' => [
            'type' => 'string',
            "analyzer" => "standard",
        ]

    );

Am I doing something wrong?

Mick

Can't override properties in trait

From the PHP documentation:

If a trait defines a property then a class can not define a property with the same name, otherwise an error is issued. It is an E_STRICT if the class definition is compatible (same visibility and initial value) or fatal error otherwise.

The properties of the Elasticquent trait (such as mappingProperties and usesTimestampsInIndex) right now cannot be overriden by directly using the trait in the model class. We would need to make a base model class use the ElastquentTrait and then override the properties.

I would suggest something like so:

public function usesTimestampsInIndex() {
    return property_exists($this, 'usesTimestampsInIndex') ? $this->usesTimestampsInIndex : true;
}

and possibly removing the property declarations in the trait to be able to directly use the trait in the model class.

Just my 2 cents!

Class 'Elasticquent\ElasticquentServiceProvider' not found in lumen project

I am using lumen framework .. added following in composer.json
"elasticquent/elasticquent": "^1.0"

and getting following error

FatalErrorException in Application.php line 162:
Class 'Elasticquent\ElasticquentServiceProvider' not found

I have registered the provider although in bootstrap.php:

$app->register(Elasticquent\ElasticquentServiceProvider::class);
$app->configure('elasticquent');

anything i am missing here?

Invalid argument supplied for foreach()

After installing Elasticsearch and Elasticquent (ES ^2.1 and elasticquent dev-master), I get the error Invalid argument supplied for foreach() on vendor/elasticsearch/elasticsearch/src/Elasticsearch/ClientBuilder.php on line 111.

Looks like the config is not being set as it returns null.

Any ideas how to get over this?

Laravel 5.2 Transport Error

Hello,

I just installed the package and ES 2.1.1. The server is running but i get an empty response at localhost:9200.(i use homestead)

When i tried to create the index, i get the error below

ErrorException in Client.php line 69:
Argument 1 passed to Elasticsearch\Client::__construct() must be an instance of Elasticsearch\Transport, array given, called in /home/vagrant/Code/Watch/vendor/elasticquent/elasticquent/src/ElasticquentTrait.php on line 60 and defined

Requires Elasticsearch-PHP < 2.1?

Composer dependencies currently indicate the core ES client library must be less than version 2.1 but the latest release is 2.1.4.

Is there a specific incompatibility we should be aware of?

Question about boosted fields in Multi Match Query

Hi,

Is it possible to apply boost on Individual fields with the caret (^) notation?
Like this sample:

{
  "multi_match" : {
    "query" : "this is a test",
    "fields" : [ "subject^3", "message" ] 
  }
}

Source: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html#CO115-1

If it's possible, how to do this with your package?
Something like that?

$client = new \Elasticsearch\Client();

$params = [
    'index' => 'default',
    'type'  => 'books'
    'body' => [
        'multi_match' => [
            'query' => 'Moby Dick',
            'fields' => ['title^3', 'author']
        ]
    ]
];

$collection = new \Elasticquent\ElasticquentResultCollection($client->search($params), new Book);

The title field is three times as important as the author field.

See adamfairholm/Elasticquent#25 for the original issue and iverberk/larasearch#73 for a similar feature request on another Laravel Elastic Search package.

Cheers,
Tortue Torche

Broken example in README

$books = Book::search('Moby Dick')->get();
echo $books->totalHits();

Does not work without specifying the index of the item you want to retrieve. This is the error, for reference:

PHP warning:  Missing argument 1 for Illuminate\Support\Collection::get(), called in /app/vendor/psy/psysh/src/Psy/ExecutionLoop/Loop.php(79) : eval()'d code on line 1 and defined in /app/bootstrap/cache/compiled.php on line 12445

Elasticsearch 2.0 support

I have been making some changes on my fork of Elasticquent to support Elasticsearch 2.0. I am still working on it but when I am done I will put up a pull request.

Having trouble searching for partial words

Hello -

I'm new to this, so I'm not having the easiest time using the package. I managed to get it running in the application, but I'm a little confused on how to do this.

I'm trying to search a field that has values like 00600005044 for 600005044 or 5044 and I'm receiving 0 results. If I search for the whole value (with leading zeros), I get the intended result back.

I have tried messing around with the mapping properties.

protected $mappingProperties = array(
   'testField' => array(
        'type' => 'string',
        'analyzer' => 'standard'
    )
);

and

protected $mappingProperties = array(
   'testField' => array(
        'type' => 'string',
        'analyzer' => 'wildcard'
    )
);

and

protected $mappingProperties = array(
   'testField' => array(
        'type' => 'integer',
        'analyzer' => 'standard'
    )
);

It seems like everything I try gives me the same results. Also, I've noticed that after changing those and running rebuildMappings() it always returns the same analyzer.

Any help would be greatly appreciated.

Is there a way of storing related models with a document?

Not sure if this is directly related to this library however I am using Elasticquent to store products and index them. Each of these products also has related models such as the user that created them, the images, the locations etc.

Is there a way using Elastiquent to store these in the same document as the product itself and possibly make them searchable? Im not sure how exactly you would go about doing this though.

I cant paginate search result

I like to use elasticquent
It is my pleasure to use elasticquent
this is my code

$orders = Order::searchByQuery(
    [
     'query' => [
      'bool' => [
       'filter' => [
        [
         'term' => [
          'price' => $query
         ]
        ]
       ]
      ]
     ]
    ]
   )->sortByDesc('id')->paginate(15);

As you can see, I want to see 15 data per page. But, I can see 10 result per page but not 15
And when I click page 2 on result page, it goes page=2 but this page=2 is not elastic search result
How can I integrate pagination with elasticquent
if you help me, it will be appreciated

Facing problem when tries to delete a record with Elasticquent

Hello, I made a delete call:
static::deleted(function ($user) { $user->deleteFromIndex(); });
gets error when I call eloquent delete
BadMethodCallException in Builder.php line 2161: Call to undefined method Illuminate\Database\Query\Builder::deleteFromIndex()

Laravel 5.2

Since laravel 5.2 the dev-master commits are broken.

I get the following error:

Fatal error: Class 'ElasticquentResultCollection' not found in /vendor/elasticquent/elasticquent/src/ElasticquentTrait.php on line 253

No way to get [sort] field. Can we just get raw results?

I have a model with this mapping:

    // elasticquent stuff
    public function getIndexDocumentData()
    {
        $address = $this->address;
        if(empty($address) || empty($this->active))return false;
        return array(
            'id'            => $this->id,
            'name'          => $this->name,
            'type'          => $this->type,
            'phone'         => $this->phone,
            'url'           => $this->url,
            'has_chive'     => $this->has_chive,
            'coordinates'      =>[
                'lat'   => $address->latitude,
                'lon'  => $address->longitude
            ],
            'active'        => 1,
            'full_address'  => $address->street.(empty($address->street_2) ? '' : "\n".$address->street_2)."\n".implode(array_filter([$address->city, $address->state, $address->zip, $address->country]), ', ')
        );
    }

    protected $mappingProperties = [
        'name' => [
            'type' => 'string',
            "analyzer" => "standard",
        ],
        'type' => [
            'type' => 'string',
            'index' => 'not_analyzed'
        ],
        'phone' => [
            'type' => 'string',
            'index' => 'no'
        ],
        'url' => [
            'type' => 'string',
            'index' => 'no'
        ],
        'has_chive' => [
            'type' => 'boolean'
        ],
        'coordinates' => [
            'type' => 'geo_point'
        ],
        'full_address' => [
            'type' => 'string',
            'index' => 'no'
        ],
        'active'    => [
            'type'  => 'string',
            'index' => 'not_analyzed'
        ],
    ];

I'm using this query:

{
    "query" : {
        "filtered" : {
            "filter": {
                "geo_distance": {
                    "type": "indexed",
                    "distance": "200mi",
                    "coordinates": {
                        "lat": 38.973370,
                        "lon": -95.243555
                    }
                }
            }

        }
    },
    "sort" : [
        {
            "_geo_distance" : {
                "coordinates" : {
                        "lat": 38.973370,
                        "lon": -95.243555
                    },
                "order" : "asc",
                "unit" : "mi"
            }
        }
    ]
}

I get raw documents that look like:

{
        "_index": "default",
        "_type": "locations",
        "_id": "276",
        "_score": null,
        "_source": {
          "id": 276,
          "name": "The Pourhouse",
          "type": "bar",
          "phone": "",
          "url": "",
          "has_chive": 1,
          "coordinates": {
            "lat": 38.994778,
            "lon": -94.714162
          },
          "active": 1,
          "full_address": "7405 Nieman Road\nShawnee, Kansas, 662144463, United States"
        },
        "sort": [
          28.46511040816118
        ]
      },

however, when using elasticquent, everything that's not in _source is not accessible. Custom getters exist for _score, but nothing else. It would be great if we could get the entire document as above, rather than a stripped down version. Especially since I would much rather prefer to use Location::complexSearch($search)->toJson() rather than iterating through each row and using something like ->documentSort() in a loop.

Maybe we can leverage /config/elasticquent.php to create an option to simply return the raw data?

If this interests you, I can create a PR. I just might do this anyway, since I need this functionality for a project.

Laravel 5.1.* Update Problem

Hi everybody,

I'am using laravel 5.1.*. I was using Elasticquent in my project to this day.
But in today I run "composer update" and got this error.

Please Help Me.

Your requirements could not be resolved to an installable set of packages.

Problem 1
- Conclusion: remove laravel/framework v5.1.28
- Conclusion: don't install laravel/framework v5.1.28
- Conclusion: don't install laravel/framework v5.1.27
- Conclusion: don't install laravel/framework v5.1.26
- Conclusion: don't install laravel/framework v5.1.25
- Conclusion: don't install laravel/framework v5.1.24
- Conclusion: don't install laravel/framework v5.1.23
- Conclusion: don't install laravel/framework v5.1.22
- Conclusion: don't install laravel/framework v5.1.21
- Conclusion: don't install laravel/framework v5.1.20
- Conclusion: don't install laravel/framework v5.1.19
- Conclusion: don't install laravel/framework v5.1.18
- Conclusion: don't install laravel/framework v5.1.17
- Conclusion: don't install laravel/framework v5.1.16
- Conclusion: don't install laravel/framework v5.1.15
- Conclusion: don't install laravel/framework v5.1.14
- Conclusion: don't install laravel/framework v5.1.13
- Conclusion: don't install laravel/framework v5.1.12
- Conclusion: don't install laravel/framework v5.1.11
- Conclusion: don't install laravel/framework v5.1.10
- Conclusion: don't install laravel/framework v5.1.9
- Conclusion: don't install laravel/framework v5.1.8
- Conclusion: don't install laravel/framework v5.1.7
- Conclusion: don't install laravel/framework v5.1.6
- Conclusion: don't install laravel/framework v5.1.5
- Conclusion: don't install laravel/framework v5.1.4
- Conclusion: don't install laravel/framework v5.1.3
- Installation request for elasticquent/elasticquent 1.0.5 -> satisfiable by elasticquent/elasticquent[v1.0.5].
- Conclusion: don't install laravel/framework v5.1.2
- Conclusion: don't install laravel/framework v5.1.1
- elasticquent/elasticquent v1.0.5 requires illuminate/config ~4.2|~5.2 -> satisfiable by illuminate/config[v4.2.1, v4.2.12, v4.2.16, v4.2.17, v4.2.2, v4.2.3, v4.2.4, v4.2.5, v4.2.6, v4.2.7, v4.2.8, v4.2.9, v5.2.0, v5.2.6, v5.2.7].
- don't install illuminate/config v4.2.1|don't install laravel/framework v5.1.0
- don't install illuminate/config v4.2.12|don't install laravel/framework v5.1.0
- don't install illuminate/config v4.2.16|don't install laravel/framework v5.1.0
- don't install illuminate/config v4.2.17|don't install laravel/framework v5.1.0
- don't install illuminate/config v4.2.2|don't install laravel/framework v5.1.0
- don't install illuminate/config v4.2.3|don't install laravel/framework v5.1.0
- don't install illuminate/config v4.2.4|don't install laravel/framework v5.1.0
- don't install illuminate/config v4.2.5|don't install laravel/framework v5.1.0
- don't install illuminate/config v4.2.6|don't install laravel/framework v5.1.0
- don't install illuminate/config v4.2.7|don't install laravel/framework v5.1.0
- don't install illuminate/config v4.2.8|don't install laravel/framework v5.1.0
- don't install illuminate/config v4.2.9|don't install laravel/framework v5.1.0
- don't install illuminate/config v5.2.0|don't install laravel/framework v5.1.0
- don't install illuminate/config v5.2.6|don't install laravel/framework v5.1.0
- don't install illuminate/config v5.2.7|don't install laravel/framework v5.1.0
- Installation request for laravel/framework 5.1.* -> satisfiable by laravel/framework[v5.1.0, v5.1.1, v5.1.10, v5.1.11, v5.1.12, v5.1.13, v5.1.14, v5.1.15, v5.1.16, v5.1.17, v5.1.18, v5.1.19, v5.1.2, v5.1.20, v5.1.21, v5.1.22, v5.1.23, v5.1.24, v5.1.25, v5.1.26, v5.1.27, v5.1.28, v5.1.3, v5.1.4, v5.1.5, v5.1.6, v5.1.7, v5.1.8, v5.1.9].

Chunk method does not work

I am experiencing a bug where the chunk() method for collections results in the error, Missing argument 2 for Elasticquent\ElasticquentResultCollection::__construct(), called in /home/vagrant/code/aer-web/vendor/laravel/framework/src/Illuminate/Support/Collection.php on line 658 and defined.

I am using Laravel 5.1 and my code is as follows:

$query = [
     'bool' => [
         'must' => [
             'multi_match' => [
                 'query' => $term,
                 'fields' => [
                     'title^5',
                     'blurb^3',
                     'description',
                     'location',
                     'zipcode',
                 ],
            ],
        ],
    ],
]; 
$campaigns = Campaign::searchByQuery($query);
dd($campaigns->chunk(2));

The full error is as follows:

ErrorException Missing argument 2 for Elasticquent\ElasticquentResultCollection::__construct(), called in /home/vagrant/code/aer-web/vendor/laravel/framework/src/Illuminate/Support/Collection.php on line 658 and defined
    vendor/elasticquent/elasticquent/src/ElasticquentResultCollection.php:21 Illuminate\Foundation\Bootstrap\HandleExceptions::handleError
    vendor/elasticquent/elasticquent/src/ElasticquentResultCollection.php:21 Elasticquent\ElasticquentResultCollection::__construct
    vendor/laravel/framework/src/Illuminate/Support/Collection.php:658 Illuminate\Support\Collection::chunk
    app/Http/Controllers/SearchController.php:48 App\Http\Controllers\SearchController::show
    [internal]:0 call_user_func_array
    vendor/laravel/framework/src/Illuminate/Routing/Controller.php:256 Illuminate\Routing\Controller::callAction
    vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php:164 Illuminate\Routing\ControllerDispatcher::call
    vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php:112 Illuminate\Routing\ControllerDispatcher::Illuminate\Routing\{closure}
    [internal]:0 call_user_func
    vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:139 Illuminate\Pipeline\Pipeline::Illuminate\Pipeline\{closure}
    [internal]:0 call_user_func
    vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:103 Illuminate\Pipeline\Pipeline::then
    vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php:114 Illuminate\Routing\ControllerDispatcher::callWithinStack
    vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php:69 Illuminate\Routing\ControllerDispatcher::dispatch
    vendor/laravel/framework/src/Illuminate/Routing/Route.php:201 Illuminate\Routing\Route::runWithCustomDispatcher
    vendor/laravel/framework/src/Illuminate/Routing/Route.php:134 Illuminate\Routing\Route::run
    vendor/laravel/framework/src/Illuminate/Routing/Router.php:704 Illuminate\Routing\Router::Illuminate\Routing\{closure}
    [internal]:0 call_user_func
    vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:139 Illuminate\Pipeline\Pipeline::Illuminate\Pipeline\{closure}
    [internal]:0 call_user_func
    vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:103 Illuminate\Pipeline\Pipeline::then
    vendor/laravel/framework/src/Illuminate/Routing/Router.php:706 Illuminate\Routing\Router::runRouteWithinStack
    vendor/laravel/framework/src/Illuminate/Routing/Router.php:671 Illuminate\Routing\Router::dispatchToRoute
    vendor/laravel/framework/src/Illuminate/Routing/Router.php:631 Illuminate\Routing\Router::dispatch
    vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:229 Illuminate\Foundation\Http\Kernel::Illuminate\Foundation\Http\{closure}
    [internal]:0 call_user_func
    vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:139 Illuminate\Pipeline\Pipeline::Illuminate\Pipeline\{closure}
    vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php:50 Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::handle
    [internal]:0 call_user_func_array
    vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:124 Illuminate\Pipeline\Pipeline::Illuminate\Pipeline\{closure}
    vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php:54 Illuminate\View\Middleware\ShareErrorsFromSession::handle
    [internal]:0 call_user_func_array
    vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:124 Illuminate\Pipeline\Pipeline::Illuminate\Pipeline\{closure}
    vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php:62 Illuminate\Session\Middleware\StartSession::handle
    [internal]:0 call_user_func_array
    vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:124 Illuminate\Pipeline\Pipeline::Illuminate\Pipeline\{closure}
    vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php:37 Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::handle
    [internal]:0 call_user_func_array
    vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:124 Illuminate\Pipeline\Pipeline::Illuminate\Pipeline\{closure}
    vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php:59 Illuminate\Cookie\Middleware\EncryptCookies::handle
    [internal]:0 call_user_func_array
    vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:124 Illuminate\Pipeline\Pipeline::Illuminate\Pipeline\{closure}
    app/Http/Middleware/CheckForMaintenanceMode.php:43 App\Http\Middleware\CheckForMaintenanceMode::handle
    [internal]:0 call_user_func_array
    vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:124 Illuminate\Pipeline\Pipeline::Illuminate\Pipeline\{closure}
    [internal]:0 call_user_func
    vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:103 Illuminate\Pipeline\Pipeline::then
    vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:118 Illuminate\Foundation\Http\Kernel::sendRequestThroughRouter
    vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:86 Illuminate\Foundation\Http\Kernel::handle
    public/index.php:54 [main]

Issue with pivot relations

Hello,

not sure if it comes from an issue with my models or the last recent batch of commits.

The origin of the error is in loadRelationsAttributesRecursive in ElasticquentTrait.php
at $relation->match

$models = static::hydrateRecursive($relation->getModel(), $value, $relation);

                        // Unset attribute before match relation
                        unset($model[$key]);
                        $relation->match([$model], $models, $key);

I am getting the following error

ErrorException in BelongsToMany.php line 503:
Trying to get property of non-object

more specifically

$dictionary[$result->pivot->$foreign][] = $result;

in BelongsToMany, buildDictionary

It is trying to access the pivot which doesnt exist in the $result

In my case the result is a Location object
the $foreign is a company_id key
the relation with the company table is set but is empty

Before the hydrate pulls it was working fine.
Any idea? Thanks!

Let me know if you need more details:

Here is my model setup

Company model, many to many with a Location model.
there is a pivot table between both

Company has a locations method

public function locations()
    {
        return $this->belongsToMany('App\Location')->withPivot('is_premium');
    }

Location has a companies method..

/**
     * The companies linked to the locations
     */
    public function companies()
    {
        return $this->belongsToMany('App\Company');
    }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.