Giter VIP home page Giter VIP logo

plastic's Introduction

Plastic Logo

Plastic is an Elasticsearch ODM and mapper for Laravel. It renders the developer experience more enjoyable while using Elasticsearch, by providing a fluent syntax for mapping, querying, and storing eloquent models.

License Build Status StyleCI

This package is still under active development and may change.

For Elasticsearch v2 please refer to version < 0.4.0.

Installing Plastic

composer require sleimanx2/plastic

If you are using Laravel >=5.5 the service provider will be automatically discovered otherwise we need to add the plastic service provider to config/app.php under the providers key:

Sleimanx2\Plastic\PlasticServiceProvider::class

Finally we need to run:

php artisan vendor:publish

This will create a config file at config/plastic.php and a mapping directory at database/mappings.

Usage

To get started, enable searching capabilities in your model by adding the Sleimanx2\Plastic\Searchable trait:

use Sleimanx2\Plastic\Searchable;

class Book extends Model
{
    use Searchable;
}

Defining what data to store.

By default, Plastic will store all visible properties of your model, using $model->toArray().

In addition, Plastic provides you with two ways to manually specify which attributes/relations should be stored in Elasticsearch.

1 - Providing a searchable property to our model

public $searchable = ['id', 'name', 'body', 'tags', 'images'];

2 - Providing a buildDocument method

public function buildDocument()
{
    return [
        'id' => $this->id,
        'tags' => $this->tags
    ];
}

Custom elastic type name

By the default Plastic will use the model table name as the model type. You can customize it by adding a $documentType property to your model:

public $documentType = 'custom_type';

Custom elastic index name

By the default Plastic will use the index defined in the configuration file. You can customize in which index your model data will be stored by setting the $documentIndex property to your model:

public $documentIndex = 'custom_index';

Plastic automatically syncs model data with elastic when you save or delete your model from our SQL DB, however this feature can be disabled by adding public $syncDocument = false to your model.

Its important to note that manual document update should be performed in multiple scenarios:

1 - When you perform a bulk update or delete, no Eloquent event is triggered, therefore the document data won't be synced.

2 - Plastic doesn't listen to related models events (yet), so when you update a related model's content you should consider updating the parent document.

Saving a document

$book = Book::first()->document()->save();

Partial updating a document

$book = Book::first()->document()->update();

Deleting a document

$book = Book::first()->document()->delete();

Saving documents in bulk

Plastic::persist()->bulkSave(Tag::find(1)->books);

Deleting documents in bulk

$authors = Author::where('age','>',25)->get();

Plastic::persist()->bulkDelete($authors);

Plastic provides a fluent syntax to query Elasticsearch which leads to compact readable code. Lets dig into it:

$result = Book::search()->match('title','pulp')->get();

// Returns a collection of Book Models
$books = $result->hits();

// Returns the total number of matched documents
$result->totalHits();

// Returns the highest query score
$result->maxScore();

//Returns the time needed to execute the query
$result->took();

To get the raw DSL query that will be executed you can call toDSL():

$dsl = Book::search()->match('title','pulp')->toDSL();

Pagination

$books = Book::search()
    ->multiMatch(['title', 'description'], 'ham on rye', ['fuzziness' => 'AUTO'])
    ->sortBy('date')
    ->paginate();

You can still access the result object after pagination using the result method:

$books->result();

Bool Query

User::search()
    ->must()
        ->term('name','kimchy')
    ->mustNot()
        ->range('age',['from'=>10,'to'=>20])
    ->should()
        ->match('bio','developer')
        ->match('bio','elastic')
    ->filter()
        ->term('tag','tech')
    ->get();

Nested Query

$contain = 'foo';

Post::search()
    ->multiMatch(['title', 'body'], $contain)
    ->nested('tags', function (SearchBuilder $builder) use ($contain) {
        $builder->match('tags.name', $contain);
    })->get();

Check out this documentation of supported search queries within Plastic and how to apply unsupported queries.

Change index on the fly

To switch to a different index for a single query, simply use the index method.

$result = Book::search()->index('special-books')->match('title','pulp')->get();
$result = User::search()
    ->match('bio', 'elastic')
    ->aggregate(function (AggregationBuilder $builder) {
        $builder->average('average_age', 'age');
    })->get();

$aggregations = $result->aggregations();

Check out this documentation of supported aggregations within plastic and how to apply unsupported aggregations.

Plastic::suggest()->completion('tag_suggest', 'photo')->get();

The suggestions query builder can also be accessed directly from the model as well:

//this be handy if you have a custom index for your model
Tag::suggest()->term('tag_term','admin')->get();

Mappings are an important aspect of Elasticsearch. You can compare them to indexing in SQL databases. Mapping your models yields better and more efficient search results, and allows us to use some special query functions like nested fields and suggestions.

Generate a Model Mapping

php artisan make:mapping "App\User"

The new mapping will be placed in your database/mappings directory.

Mapping Structure

A mapping class contains a single method map. The map method is used to map the given model fields.

Within the map method you may use the Plastic Map builder to expressively create field maps. For example, let's look at a sample mapping that creates a Tag model map:

use Sleimanx2\Plastic\Map\Blueprint;
use Sleimanx2\Plastic\Mappings\Mapping;

class AppTag extends Mapping
{
    /**
     * Full name of the model that should be mapped
     *
     * @var string
     */
    protected $model = App\Tag::class;

    /**
     * Run the mapping.
     *
     * @return void
     */
    public function map()
    {
        Map::create($this->getModelType(), function (Blueprint $map) {
            $map->string('name')->store('true')->index('analyzed');

            // instead of the fluent syntax we can use the second method argument to fill the attributes
            $map->completion('suggestion', ['analyzer' => 'simple', 'search_analyzer' => 'simple']);
        },$this->getModelIndex());
    }
}

To learn about all of the methods available on the Map builder, check out this documentation.

Run Mappings

Running the created mappings can be done using the Artisan console command:

php artisan mapping:run

Updating Mappings

If your update consists only of adding a new field mapping you can always update our model map with your new field and run:

php artisan mapping:rerun

The mapping for existing fields cannot be updated or deleted, so you'll need to use one of following techniques to update existing fields.

1 - Create a new index

You can always create a new Elasticsearch index and re-run the mappings. After running the mappings you can use the bulkSave method to sync your SQL data with Elasticsearch.

2 - Using aliases

Its recommended to create your Elasticsearch index with an alias to ease the process of updating your model mappings with zero downtime. To learn more check out:

https://www.elastic.co/blog/changing-mapping-with-zero-downtime

Populating an index with searchable models can be done by running an Artisan console command :

php artisan plastic:populate [--mappings][--index=...][--database=...]
  • --mappings Create the models mappings before populating the index
  • --database=... Database connection to use for mappings instead of the default one
  • --index=... Index to populate instead of the default one

The list of models from which to recreate the documents has to be configured per index in config/plastic.php:

    'populate' => [
        'models' => [
            // Models for the default index
            env('PLASTIC_INDEX', 'plastic') => [
                App\Models\Article::class,
                App\Models\Page::class,
            ],
            // Models for the index "another_index"
            'another_index' => [
                App\Models\User::class,
            ],
        ],
    ],

You can access the Elasticsearch client to manage your indices and aliases as follows:

$client = Plastic::getClient();

//index delete
$client->indices()->delete(['index'=> Plastic::getDefaultIndex()]);
//index create
$client->indices()->create(['index' => Plastic::getDefaultIndex()]);

More about the official elastic client : https://github.com/elastic/elasticsearch-php

Contributing

Thank you for contributing, The contribution guide can be found Here.

License

Plastic is open-sourced software licensed under the MIT license.

To Do

Search Query Builder

  • implement Boosting query
  • implement ConstantScore query
  • implement DisMaxQuery query
  • implement MoreLikeThis query (with raw eloquent models)
  • implement GeoShape query

Aggregation Query Builder

  • implement Nested aggregation
  • implement ExtendedStats aggregation
  • implement TopHits aggregation

Mapping

  • Find a seamless way to update field mappings with zero downtime with aliases

General

  • Better query builder documentation

plastic's People

Contributors

atodd avatar bjrnblm avatar chellman avatar daverdalas avatar ellisio avatar helloiamlukas avatar henriquebremenkanp avatar jamesgraham avatar jaybizzle avatar jfossey avatar killtw avatar mschreck avatar mxp100 avatar reynotech avatar sergeysetti avatar sgtpepper9907 avatar shaoshiva avatar sleimanx2 avatar tobias-kuendig avatar zhwei 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

plastic's Issues

Aggregations missing in Paginator

Hi,

thank you very much for this wonderful package. I started developing the same thing, but this is much better and more sophisticated.

There is a small "bug" in your paginator. It is using parents "toArray" method that of course doesn´t know anything about aggregations. Maybe you could override the function this way:

public function toArray()
    {
        return [
            'total' => $this->total(),
            'per_page' => $this->perPage(),
            'current_page' => $this->currentPage(),
            'last_page' => $this->lastPage(),
            'next_page_url' => $this->nextPageUrl(),
            'prev_page_url' => $this->previousPageUrl(),
            'from' => $this->firstItem(),
            'to' => $this->lastItem(),
            'data' => $this->items->toArray(),
            'aggregations' => $this->result->aggregations(),
        ];
    }

Cannot install plastic

At first plastic could not install due to a dependency to laravel 5.2. After upgrading to 5.2 composer require sleimanx2/plastic downloaded the files into vendor/sleimanx2

Running php artisan vendor:publish did not publish any files into config/ nor did it create a database/mappings directory. I went ahead and created those files/directories manually.

Still having issues... There are no Plastic related commands when running php artisan and running$model->save() throws an Exception: Class plastic does not exist

What am I missing?

Models should be in separate indices

According to this page, one shouldn't mix different types of data in a single index. By default, Plastic stores all models in a single index, and differentiates based on type.

However, the underlying Lucene instance flattens out all mappings, causing conflict issues like #31. I have also started to run into issues like this.

Totally understanding how big a change this would be, I reckon we should think about changing this package to use separate indices for each model type by default. I'd be happy to tackle the work and open a PR.

Thoughts?

Publishing assets by provider fails.

php artisan vendor:publish --provider="Sleimanx2\Plastic\PlasticServiceProvider"
Can't locate path: <{my project root}/vendor/sleimanx2/plastic/src/resources/config.php>
Can't locate path: <{my project root}/vendor/sleimanx2/plastic/src/resources/database>
Publishing complete for tag []!

How do I setting for custom analyzers?

Hi. I'm newbie.
I found anything in readme, so I cant find anyway to custom analyzers for my index.
Can u help me?
Example, I want to have a custom analyzers bellow:
"analyzer": { "did_you_mean": { "filter": ["lowercase"], "char_filter": ["html_strip"], "type": "custom", "tokenizer": "vi_tokenizer" }, "autocomplete": { "filter": ["lowercase", "autocomplete_filter"], "char_filter": ["html_strip"], "type": "custom", "tokenizer": "standard" }, "default": { "filter": ["lowercase", "stopwords_filter", "stemmer_filter"], "char_filter": ["html_strip"], "type": "custom", "tokenizer": "standard" } }
Thanks for help.

Welcome to laravel-scout

Greetings! For a long time watching your project, now there is an official project at the Scout laravel. It is very similar to yours. Even there is a feeling that an idea borrowed from you :)
I would like to invite you to our disskussii for the development of Scout and possible further merger. Your project is much more mature and well developed.
What can be said about Scout. We are looking forward to your participation and experience!
laravel/scout#7

ElasticSearch 5 Support

I was wondering if you are planning to add support for ElasticSearch 5. The Unit Tests don't seem to throw any errors when i upgrade the dependencies locally.

Dependencies

ongr/elasticsearch-dsl          v2.2.0
elasticsearch/elasticsearch     v5.1.0

Tests

PHPUnit 4.8.32 by Sebastian Bergmann and contributors.

Runtime:        PHP 7.0.12
Configuration:  C:\Users\Nevoxx\Desktop\plastic\phpunit.xml
Warning:        The Xdebug extension is not loaded
                No code coverage will be generated.

...............................................................  63 / 141 ( 44%)
............................................................... 126 / 141 ( 89%)
...............

Time: 804 ms, Memory: 16.00MB

OK (141 tests, 246 assertions)

Fetch model from ID when filling results

At the moment, if I specify only certain fields to be indexed (with $searchable for example), only those fields will be filled in search results.

EloquentFiller::fill() should re-retrieve the models from the DB fresh, and use those to populate the results.

An example of such a modification:

public function fill(Model $model, Result $result)
{
    // Get all the _id values from the elastic results
    $ids = $result->hits()->pluck('_id')->toArray();

    // Re-fetch all those models in a single query
    $hits = $model->newQueryWithoutScopes()->whereIn($model->getQualifiedKeyName(), $ids)->get();

    // Populate the results
    $result->setHits($hits);
}

The reason I haven't made this a PR is because I can see that EloquentFiller is doing a number of other things besides just spinning up Model instances. If you could enumerate what else it's doing for me I am happy to do the work. I'm using this package quite extensively :)

mapper conflict with existing mapping in other types

Thank you for the great work. I have my initial fields mapping, but then I realized later I put on the wrong field. I tried to change the field mapping through php artisan mapping:run command, but got mapper conflict error message. How can I delete the initial mapping? How to change the mapped fields?

Please help me to solve this.

Here is the windows command prompt error message:

C:\xampp\htdocs\search>php artisan mapping:run

[Elasticsearch\Common\Exceptions\BadRequest400Exception] illegal_argument_exception: Mapper for [description] conflicts with existing mapping in other types:
[mapper [description] has different [store] values, mapper [description] has different [store_term_vector] values, mapper [description] has different [store_term_vector_offsets] values, mapper [description] has different [store_term_vector_positions] values]

[Elasticsearch\Common\Exceptions\BadRequest400Exception]
{"error":{"root_cause":[{"type":"illegal_argument_exception","reason":"Mapper for [description] conflicts with existing mapping in other types:\n[mapper [description] has different [store] values, mapper [description] has different [store_term_vector] values, mapper [description] has different [store_term_vector_offsets] values, mapper [description] has different [store_term_vector_positions] values]"}],"type":"illegal_argument_exception","reason":"Mapper for [description] conflicts with existing mapping in other types:\n[mapper [description] has different [store] values, mapper [description] has different [store_term_vector] values, mapper [description] has different [store_term_vector_offsets] values, mapper [description] has different [store_term_vector_positions] values]"},"status":400}

Thank you.

Relations search

I want to use plastic to search in model that has the following structure:

Activity (Model)
User (Model)
Category (Model)

one User can have many Activity.
I am using MySQL for DB.

I want to use the Searchable trait (elasticsearch) only in the Activity model, but in the same time to be able to make queries like:

get all activities where the user's name is joe.

Also when the user is updated it should update the index for the Activity.

Is this even possible and if yes how?

Also if someone has better idea of how to develop this I am open for proposals. 🙂

@jamesgraham

Get count without hits | _count | totalHits

Can I get totalHits (count) without hits?
I like this http://localhost:9200/plastic/books/_count?q=title:pulp bacause _count faster than _search.

The logic with _search (hits.total).

Book::search()
    ->match('title', 'pulp')
    ->get()
    ->totalHits();

Get only one column

I have this query

  $other = Company::search()
                ->geoDistance('location', 22000, $center)
                ->mustNot()
                ->match('new_slug', $slug)
                ->sortby('dishes_count', 'desc')
                ->size(50)
                ->get()->hits()->pluck('id')->toarray();

It's working nice and all, only when I get the companies, I get it with all the relations as well, and those relations have translates and so on. Is there a way to get only the id's of the companies without all the other trash?

No alive nodes found in your cluster

hi...
i'm using this package (v0.1.6) on laravel 5.1
but i see this error alltimes...
No alive nodes found in your cluster

'hosts' => ['127.0.0.1:9200']

can you help me?
i'm newbie in elasticsearch

No alive nodes found in your cluster

While run the package installation it giving error - NoNodesAvailableException in StaticNoPingConnectionPool.php line 51 What is the best way to resolve this. Log contain the following data -
log.WARNING: Curl exception encountered. [] []
log.WARNING: Request Failure: {"method":"GET","uri":"http://192.168.0.114:9200/plastic/books/_search","headers":{"host":["192.168.0.114:9200"]},"HTTP code":null,"duration":0.218,"error":"cURL error 7: Failed to connect to 192.168.0.114 port 9200: Connection refused"} []
log.WARNING: Response [null] []
log.WARNING: Marking node 192.168.0.114:9200 dead. [] []
log.WARNING: Retries left? true [] []
log.CRITICAL: No alive nodes found in cluster [] []

Is any solution for this. I am using windows 7 and laravel latest 5.2

Why have to do bulk deleting from the relative model?

Thank you for the great work, it's the best for laravel with elasticsearch!
In the example, I should do like this to bulk delete documents:
$author->document()->bulkDelete($author->books);

But how can I just achieve this:
$books = Books::all(); bulkDelete($books);

Thank you!

preserve_position_increments Completion mapping

My mapping is
$map->completion('company_name_suggest',['analyzer' => 'simple', 'search_analyzer'=>'simple', 'preserve_position_increments' => 'false']);

but the preserve_position_increments remains true. Any suggestions ?

Filling a model with a date attribute fails

I have a date field set in the model under $dates. This is passed to the index with buildDocument.

I have tried defining the mapping as a date and a string but regardless it gets stored in the index as:

   "scheduled_start_time" : {
      "date" : "2017-02-04 18:45:00.000000",
      "timezone_type" : 3,
      "timezone" : "UTC"
    },

This means if I wish to sort on it I must use scheduled_start_time.date
The bigger issue is that when retrieving a search with ->hits() this gives me an Eloquent error because the types do not match. What am I doing wrong?

ErrorException in HasAttributes.php line 700:
preg_match() expects parameter 2 to be string, array given
in HasAttributes.php line 700
at HandleExceptions->handleError(2, 'preg_match() expects parameter 2 to be string, array given', '/home/vagrant/Code/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php', 700, array('value' => array('date' => '2017-02-04 09:00:00.000000', 'timezone_type' => 3, 'timezone' => 'UTC'))) in ErrorHandler.php line 36
at Raven_Breadcrumbs_ErrorHandler->handleError(2, 'preg_match() expects parameter 2 to be string, array given', '/home/vagrant/Code/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php', 700, array('value' => array('date' => '2017-02-04 09:00:00.000000', 'timezone_type' => 3, 'timezone' => 'UTC')))
at preg_match('/^(\d{4})-(\d{1,2})-(\d{1,2})$/', array('date' => '2017-02-04 09:00:00.000000', 'timezone_type' => 3, 'timezone' => 'UTC')) in HasAttributes.php line 700
at Model->isStandardDateFormat(array('date' => '2017-02-04 09:00:00.000000', 'timezone_type' => 3, 'timezone' => 'UTC')) in HasAttributes.php line 680
at Model->asDateTime(array('date' => '2017-02-04 09:00:00.000000', 'timezone_type' => 3, 'timezone' => 'UTC')) in HasAttributes.php line 711
at Model->fromDateTime(array('date' => '2017-02-04 09:00:00.000000', 'timezone_type' => 3, 'timezone' => 'UTC')) in HasAttributes.php line 525
at Model->setAttribute('scheduled_start_time', array('date' => '2017-02-04 09:00:00.000000', 'timezone_type' => 3, 'timezone' => 'UTC')) in Enums.php line 52

does plastic work in Laravel 5.1?

Hello.

I tried to install plastic in Laravel 5.1 and I got that errors:

Problem 1
- Installation request for sleimanx2/plastic ^0.2.0 -> satisfiable by sleimanx2/plastic[v0.2.0].
- Conclusion: remove laravel/framework v5.1.40
- Conclusion: don't install laravel/framework v5.1.40
- sleimanx2/plastic v0.2.0 requires illuminate/pagination 5.2.* -> satisfiable by illuminate/pagination[v5.2.0, v5.2.19, v5.2.21, v5.2.24, v5.2.25, v5.2.26, v5.2.27, v5.2.28, v5.2.31, v5.2.32, v5.2.37, v5.2.43, v5.2.45, v5.2.6, v5.2.7].
- don't install illuminate/pagination v5.2.0|don't install laravel/framework v5.1.40
- don't install illuminate/pagination v5.2.19|don't install laravel/framework v5.1.40
- don't install illuminate/pagination v5.2.21|don't install laravel/framework v5.1.40
- don't install illuminate/pagination v5.2.24|don't install laravel/framework v5.1.40
- don't install illuminate/pagination v5.2.25|don't install laravel/framework v5.1.40
- don't install illuminate/pagination v5.2.26|don't install laravel/framework v5.1.40
- don't install illuminate/pagination v5.2.27|don't install laravel/framework v5.1.40
- don't install illuminate/pagination v5.2.28|don't install laravel/framework v5.1.40
- don't install illuminate/pagination v5.2.31|don't install laravel/framework v5.1.40
- don't install illuminate/pagination v5.2.32|don't install laravel/framework v5.1.40
- don't install illuminate/pagination v5.2.37|don't install laravel/framework v5.1.40
- don't install illuminate/pagination v5.2.43|don't install laravel/framework v5.1.40
- don't install illuminate/pagination v5.2.45|don't install laravel/framework v5.1.40
- don't install illuminate/pagination v5.2.6|don't install laravel/framework v5.1.40
- don't install illuminate/pagination v5.2.7|don't install laravel/framework v5.1.40
- Installation request for laravel/framework == 5.1.40.0 -> satisfiable by laravel/framework[v5.1.40].

Thanks

Bulk Indexing and GeoPoint

Hey. I just came across this package, and it's exactly what I'm looking for ( Scout is not mature enough for what I need ).

How can I batch index collections ? $tag->document()->bulkSave($tag->books); works if you pass it with a relationship. What if I have 100k items without any linking?

Also, can I use Edge NGram Tokenizer with this?

Thanks in advance. Have a good one

[Proposal] Move Maps to `App\Mappings` directory

I was thinking that it might be a bit better to have the mappings saved within the app directory for a couple of reasons:

  1. They're not really related to the database. I mean, I can see the logic but they don't seem to me to fit in the database directory.
  2. They're pretty important to the functioning of the application. Seems like it'd be good to keep them with the rest of the application logic.

I'd be happy to prepare a PR if you think that this is a good idea.

:)

is it possible to use auto-generate id by elasticsearch?

Per elastico document, they advise to use auto generate id so is it possible to keep model id (db id) inside each document while leave the "_id" field to elasticsearch to decide? Thanks (below is a sample)

...
         {
            "_index": "sample",
            "_type": "user",
            "_id": "2",
            "_score": 1,
            "_source": {
               "first_name": "E",
               "last_name": "F",
               "id": 2
            }
         },
         {
            "_index": "sample",
            "_type": "user",
            "_id": "AVlm__uB9pLpNbCey5qK",
            "_score": 1,
            "_source": {
               "first_name": "A",
               "last_name": "B",
               "id": 3
            }
         },
...

Using this to implement a "search as you type" component?

Hello,

I have this setup and configured correctly; and indexing all of our documents we want to search.

For example, we have this index:

{
   "_id":"1",
   "_index":"acme",
   "_score":1.0,
   "_source":{
      "created_at":"2017-01-19 21:18:43",
      "first_name":"Andrew",
      "full_name":"Andrew Ellis",
      "id":1,
      "last_name":"Ellis",
      "organization":{
         "created_at":"2017-01-19 21:18:18",
         "id":1,
         "name":"EllisDev",
         "number_vendor_id":2,
         "owner":{
            "created_at":"2017-01-19 21:18:17",
            "first_name":"Andrew",
            "full_name":"Andrew Ellis",
            "id":1,
            "last_name":"Ellis",
            "photo_url":"https://gravatar.com/avatar/eb1a3a020c1d5c3073cf789ffa245b94.png?s=200&d=mm",
            "updated_at":"2017-01-19 21:18:19"
         },
         "owner_id":1,
         "photo_url":"https://gravatar.com/avatar/eb1a3a020c1d5c3073cf789ffa245b94.png?s=200&d=mm",
         "seat_credits":0,
         "stripe_plan":"base",
         "updated_at":"2017-01-19 21:18:31"
      },
      "organization_id":1,
      "owner":{
         "created_at":"2017-01-19 21:18:17",
         "first_name":"Andrew",
         "full_name":"Andrew Ellis",
         "id":1,
         "last_name":"Ellis",
         "photo_url":"https://gravatar.com/avatar/eb1a3a020c1d5c3073cf789ffa245b94.png?s=200&d=mm",
         "pivot":{
            "contact_id":1,
            "created_at":"2017-01-19 21:18:43",
            "role":"owner",
            "updated_at":"2017-01-19 21:18:43",
            "user_id":1
         },
         "updated_at":"2017-01-19 21:18:19"
      },
      "updated_at":"2017-01-19 21:18:43"
   },
   "_type":"contacts"
},

What I want is to be able to allow the user to type "And" and show the "Andrew Ellis" contact recored.

The only time I get any results is if I run the following:

Contact::search()->match('first_name', 'Andrew')->get();

I tried implementing the queryString via the following, but no results get returned:

Contact::search()->queryString('And*')->get();

What is the recommended way of going about this with your library?

Same GroupBy problem

Hey. I come with this problem again. I know I've asked this before, but I still couldn't find a solution. From what I understand I need to aggregate by term, My query currently looks like this

Dish::search()
            ->sortby('food_image', 'desc')
            ->aggregate(function ($builder) {
                $builder->terms('unique_dishes', 'title');
            })->get();

And this is the result

array:1 [▼
  "unique_dishes" => array:3 [▼
    "doc_count_error_upper_bound" => 31445
    "sum_other_doc_count" => 7376915
    "buckets" => array:10 [▶]
  ]
]

How do I continue from here? Any guidance would be appreciated. Thanks in advance

EloquentFiller::isMultiLevelArray() must be of the type array

Hello , I did a search for Elasticsearch, but reported this error, what can I do?

[Symfony\Component\Debug\Exception\FatalThrowableError]
Type error: Argument 1 passed to Sleimanx2\Plastic\Fillers\EloquentFiller::isMultiLevelArray() must be of the type array, integer given, called in /vendor/sleimanx2/plastic/src/Fillers/EloquentFiller.php on line 123

The query is as follows:

UserModel::search()->match('user_name', 'admin')->get()

toDSL

array:1 [
  "query" => array:1 [
    "match" => array:1 [
      "user_name" => array:1 [
        "query" => "admin"
      ]
    ]
  ]
]

Trait creation event throws "invalid request body provided" InvalidArgumentException from Guzzle

ERROR: exception 'InvalidArgumentException' with message 'Invalid request body provided' in _{project path}_vendor/guzzlehttp/ringphp/src/Client/CurlFactory.php:289 Stack trace: #0 _{project path}_vendor/guzzlehttp/ringphp/src/Client/CurlFactory.php(248): GuzzleHttp\Ring\Client\CurlFactory->addStreamingBody(Array, Array) #1 _{project path}_vendor/guzzlehttp/ringphp/src/Client/CurlFactory.php(203): GuzzleHttp\Ring\Client\CurlFactory->applyBody(Array, Array) #2 _{project path}_vendor/guzzlehttp/ringphp/src/Client/CurlFactory.php(30): GuzzleHttp\Ring\Client\CurlFactory->applyMethod(Array, Array) #3 _{project path}_vendor/guzzlehttp/ringphp/src/Client/CurlHandler.php(84): GuzzleHttp\Ring\Client\CurlFactory->__invoke(Array, Resource id #920) #4 _{project path}_vendor/guzzlehttp/ringphp/src/Client/CurlHandler.php(68): GuzzleHttp\Ring\Client\CurlHandler->_invokeAsArray(Array) #5 _{project path}_vendor/guzzlehttp/ringphp/src/Client/Middleware.php(30): GuzzleHttp\Ring\Client\CurlHandler->__invoke(Array) #6 _{project path}_vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/Connection.php(184): GuzzleHttp\Ring\Client\Middleware::GuzzleHttp\Ring\Client{closure}(Array) #7 _{project path}_vendor/elasticsearch/elasticsearch/src/Elasticsearch/Connections/Connection.php(159): Elasticsearch\Connections\Connection->Elasticsearch\Connections{closure}(Array, Object(Elasticsearch\Connections\Connection), Object(Elasticsearch\Transport), Array) #8 _{project path}_vendor/elasticsearch/elasticsearch/src/Elasticsearch/Transport.php(106): Elasticsearch\Connections\Connection->performRequest('PUT', '/plastic/descri...', Array, Array, Array, Object(Elasticsearch\Transport)) #9 _{project path}_vendor/elasticsearch/elasticsearch/src/Elasticsearch/Endpoints/AbstractEndpoint.php(80): Elasticsearch\Transport->performRequest('PUT', '/plastic/descri...', Array, Array, Array) #10 _{project path}_vendor/elasticsearch/elasticsearch/src/Elasticsearch/Client.php(911): Elasticsearch\Endpoints\AbstractEndpoint->performRequest() #11 _{project path}_vendor/sleimanx2/plastic/src/Connection.php(148): Elasticsearch\Client->index(Array) #12 _{project path}_vendor/sleimanx2/plastic/src/Persistence/EloquentPersistence.php(27): Sleimanx2\Plastic\Connection->indexStatement(Array) #13 _{project path}_vendor/sleimanx2/plastic/src/Searchable.php(40): Sleimanx2\Plastic\Persistence\EloquentPersistence->save() #14 [internal function]: App\Description::Sleimanx2\Plastic{closure}(Object(App\Description)) #15 _{project path}_vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php(221): call_user_func_array(Object(Closure), Array) #16 _{project path}_vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1679): Illuminate\Events\Dispatcher->fire('eloquent.saved:...', Object(App\Description)) #17 _{project path}_vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1514): Illuminate\Database\Eloquent\Model->fireModelEvent('saved', false) #18 _{project path}_vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1485): Illuminate\Database\Eloquent\Model->finishSave(Array) #19 _{project path}_vendor/laravel/framework/src/Illuminate/Database/Eloquent/Relations/MorphOneOrMany.php(187): Illuminate\Database\Eloquent\Model->save() #20 _{project path}_database/seeds/RuleTableSeeder.php(139): Illuminate\Database\Eloquent\Relations\MorphOneOrMany->create(Array) #21 _{project path}_vendor/laravel/framework/src/Illuminate/Database/Seeder.php(39): App\Database\Seeds\RuleTableSeeder->run() #22 _{project path}_database/seeds/RulesAndSkillsSeeder.php(18): Illuminate\Database\Seeder->call('App\Database\Se...') #23 _{project path}_vendor/laravel/framework/src/Illuminate/Database/Console/Seeds/SeedCommand.php(63): RulesAndSkillsSeeder->run() #24 _{project path}_vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(2286): Illuminate\Database\Console\Seeds\SeedCommand->Illuminate\Database\Console\Seeds{closure}() #25 _{project path}_vendor/laravel/framework/src/Illuminate/Database/Console/Seeds/SeedCommand.php(64): Illuminate\Database\Eloquent\Model::unguarded(Object(Closure)) #26 [internal function]: Illuminate\Database\Console\Seeds\SeedCommand->fire() #27 _{project path}_vendor/laravel/framework/src/Illuminate/Container/Container.php(507): call_user_func_array(Array, Array) #28 _{project path}_vendor/laravel/framework/src/Illuminate/Console/Command.php(169): Illuminate\Container\Container->call(Array) #29 _{project path}_vendor/symfony/console/Command/Command.php(256): Illuminate\Console\Command->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) #30 _{project path}_vendor/laravel/framework/src/Illuminate/Console/Command.php(155): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) #31 _{project path}_vendor/symfony/console/Application.php(791): Illuminate\Console\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) #32 _{project path}_vendor/symfony/console/Application.php(186): Symfony\Component\Console\Application->doRunCommand(Object(Illuminate\Database\Console\Seeds\SeedCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) #33 _{project path}_vendor/symfony/console/Application.php(117): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) #34 _{project path}_vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(107): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) #35 _{project path}_artisan(36): Illuminate\Foundation\Console\Kernel->handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) #36 {main} [] []

excludes and highlights

Hi !
First of all, thank you for this package, it's very handy.
I'm trying to exclude some fields from my search results. I just don't want my users to be able to see the IDs of the resources. If I was to use simple Json I would do the following :

"_source": {
    "excludes": [ "*.id" ]
},

Easy enough. But I can't figure out how to do it with plastic.
Same thing for Highlight, I see that ElasticsearchDSL package has an Highlight Endpoint, but would it be possible to use that with plastic ?

Thanks.

Xavier

Point mapping bug

In my mapping I have $map->point ('coordinates')->lat_long (TRUE)->geohash (TRUE);

In Elastic it's being saved as

 "coordinates": {
        "properties": {
          "lon": {
            "type": "double"
          },
          "lat": {
            "type": "double"
          }
        }
      },

instead of

 "coordinates": {
          "geohash": true,
          "type": "geo_point"
        },

inIndex for saving/updating etc?

Is it possible to make the inIndex method available for saving etc?

So for example Book::first()->document()->inIndex('test')->save();

Map::getFacadeAccessor() returning new instance with each call to Map facade

Thanks for a very helpful and time saving package.

I was trying to use a custom blueprint class by using Map::blueprintResolver(). This seemed to have no effect.

After a short investigation I discovered that because Map::getFacadeAccessor() is returning an object instance and Facades::resolveFacadeInstance($name) returns objects immediately without adding them to the $resolvedInstance static property.

The side effect to this that every call to the Map facade will resolve a new instance of Builder making the blueprintResolver() method un-usable.

So from my point of view if I understand everything correctly, to use the Map Facade as intended getFacadeAccessor() will need to return a object instance saved to a property in Connection or a Application container singleton.

Absolute need for 5.2?

Are there 5.2 features/bindings used, or could the composer requirement be downgraded to 5.1?

Fielddata is disabled on text fields by default

When I using this code:
$books = Book::search() ->multiMatch(['title', 'description'], 'ham on rye', ['fuzziness' => 'AUTO']) ->sortBy('date') ->paginate();
I give a error: Fielddata is disabled on text fields by default.
Can you help me to set fielddata=true

How to configure for REST to ES on AWS?

Placing my ES AWS instance endpoint (with port 80) in the hosts array of plastic php and running
php artisan mapping:run
results in:

[Elasticsearch\Common\Exceptions\Missing404Exception]
{"error":"IndexMissingException[[plastic] missing]","status":404}

Is this a supported use case, or am I just doing it wrong?

EloquentFiller::isMultiLevelArray()

Sleimanx2\Plastic\Fillers\EloquentFiller::isMultiLevelArray() must be of the type array, string given, called in \vendor\sleimanx2\plastic\src\Fillers\EloquentFiller.php on line 123

This is the query
$dishes = Dish::search()->match('name' ,'Sandwich Salami')->get();
and below is the toDSL

array:1 [▼
  "query" => array:1 [▼
    "match" => array:1 [▼
      "name" => array:1 [▼
        "query" => "Sandwich Salami"
      ]
    ]
  ]
]

The postman query
http://i.imgur.com/ZxNL4k0.png

Any ideas?

Query groupby

Hi. I could not find groupby in querybuilder. How could I achieve that?
Thanks in advance

Sortby geoDistance

This might be obvious, but I'm having troubles figuring it out.

Currently what I have is
$jobs->geoDistance('job_coordinates' , 22000, $city_coordinates);

Now how do I order them by the distance from city_coordinates ?

Thanks in advance

ES 5.1?

Seeing as how this is still under active development, have you thought about making sure this is built against the latest ES 5.1?

Upgrading composer.json to the following:

"elasticsearch/elasticsearch": "~5.1",
"ongr/elasticsearch-dsl": "dev-master"

Then running your unit tests results in a full pass. I know you probably don't want dev-master as dependency right now. But being under active development can't hurt to do so seeing as how ongr/elasticsearch-dsl is actively working on releasing their 5.x support.

$ vendor/bin/phpunit
PHPUnit 4.8.31 by Sebastian Bergmann and contributors.

Runtime:	PHP 7.0.14 with Xdebug 2.5.0
Configuration:	/Users/andrew/Developer/GitHub/ellisio/plastic/phpunit.xml

...............................................................  63 / 141 ( 44%)
............................................................... 126 / 141 ( 89%)
...............

Time: 2.72 seconds, Memory: 18.00MB

OK (141 tests, 246 assertions)

Generating code coverage report in Clover XML format ... done

Generating code coverage report in HTML format ... done

"type" is not a valid parameter.

Do you have an idea how to resolve this issue:

UnexpectedValueException in AbstractEndpoint.php line 247:
"type" is not a valid parameter. Allowed parameters are: "analyzer", "analyze_wildcard", "default_operator", "df", "explain", "fields", "fielddata_fields", "filter_path", "from", "ignore_unavailable", "allow_no_indices", "expand_wildcards", "indices_boost", "lenient", "lowercase_expanded_terms", "preference", "q", "query_cache", "request_cache", "routing", "scroll", "search_type", "size", "sort", "source", "_source", "_source_exclude", "_source_include", "terminate_after", "stats", "suggest_field", "suggest_mode", "suggest_size", "suggest_text", "timeout", "track_scores", "version", "request_cache", "client", "custom", "filter_path"

Using CURL I see that my server has entries, which are automatically placed via Plastic, but I cant read/search them using this simple example:

$search = $request->input('search');
$results = Plastic::search()->match('title',$search)->get();

The error is very obvious - replacing:

    public function getType()
    {
        return $this->type;
    }

with:

    public function getType()
    {
         return 'searchindex'; // my type
    }

works well, but thats not nice.

Looks like I forgot about something? Do you have an idea?

Class 'Input' not found

When I'm using the paginate() function, the SearchBuilder tries to call the Input facade, but this one was removed here

Standard analyzer not "analyzing"

Mapping is
$map->completion('title_suggest',['analyzer' => 'standard']);

My string is Verkäufer and I would expect the analyzer to remove the ä but it does not.

In es,
ES

Is this a package bug or I missed something ?

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.