elasticquent / Elasticquent

Maps Laravel Eloquent models to Elasticsearch types
MIT License
1.35k stars 400 forks source link

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

Open jontroncoso opened 8 years ago

jontroncoso commented 8 years ago

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.

jontroncoso commented 8 years ago

I was able to get to the sort field by overloading the newFromHitBuilder method on my model:

/* App\Location.php */
    use ElasticquentTrait {
        newFromHitBuilder as elasticquentNewFromHitBuilder;
    }
    ...
    public function newFromHitBuilder($hit = array())
    {
        if(!empty($hit['sort']))$hit['fields']['sort'] = $hit['sort'];
        return $this->elasticquentNewFromHitBuilder($hit);
    }

I technically got around this so you can close this if you like. But you might want to make this functionality more accessible. If so, feel free to to leave this open.

timgws commented 8 years ago

I don't think that this should be a configuration option.

It is preferred that configuration options of the library do not change the functionality. This way, you can be sure that calling a method will always work as expected.

Maybe a new method that returns all of the data as newFromHitBuilder currently does, except it merges in the data from _source after all the other values have been merged into another array?

oknoote commented 8 years ago

I'm running into the same problem. Without @jontroncoso 's work-around it is currently not possible to get the computed distance on distance sort (thanks for the work-around!) :)

Creating a method that returns all data would be a great addition and add more flexibility to the "power user".