You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Laravel Scout Elastic实现Elasticsearch中parent与childrens索引关联?

How to Set Up Relationships Between parents and childrens Indices in Elasticsearch with Laravel Scout Elastic

Hey there! Since you're new to Elasticsearch and using tamayo/laravel-scout-elastic in your Laravel project, let's walk through how to establish a relationship between your parents and childrens indices. Elasticsearch isn't a relational database, so we have two common patterns to choose from—nested documents and parent-child relationships—each with their own use cases. Let's cover both.

Option 1: Nested Documents (Best for "Always Query Together" Scenarios)

If you usually query parents along with their children and don't need to update children independently, nested documents are a great fit. This stores children as an array directly inside the parent document in Elasticsearch.

Step 1: Define the Eloquent Relationship

First, make sure your Laravel models have the correct Eloquent relationships (note: rename the parent model to avoid conflict with PHP's built-in Parent class):

// app/Models/ParentModel.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;

class ParentModel extends Model
{
    use Searchable;

    protected $table = 'parents';

    // Define relationship to children
    public function children()
    {
        return $this->hasMany(Children::class, 'parent_id');
    }

    // Specify the Elasticsearch index name
    public function searchableAs()
    {
        return 'parents';
    }

    // Customize data sent to Elasticsearch (include children)
    public function toSearchableArray()
    {
        $array = $this->toArray();
        // Load the children relationship and add it to the document
        $array['children'] = $this->children->toArray();
        return $array;
    }

    // Define Elasticsearch mapping for the nested field
    public function getMapping()
    {
        return [
            'properties' => [
                'id' => ['type' => 'integer'],
                'name' => ['type' => 'text'],
                // Add other parent fields as needed
                'children' => [
                    'type' => 'nested',
                    'properties' => [
                        'id' => ['type' => 'integer'],
                        'name' => ['type' => 'text'],
                        // Add other children fields as needed
                    ]
                ]
            ]
        ];
    }
}
// app/Models/Children.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Children extends Model
{
    protected $table = 'childrens';

    // Define inverse relationship to parent
    public function parent()
    {
        return $this->belongsTo(ParentModel::class, 'parent_id');
    }
}

Step 2: Create the Index Mapping

Run this Artisan command to create the index with the nested mapping (flush first if the index already exists):

# Flush existing index (if needed)
php artisan scout:flush "App\Models\ParentModel"

# Import parent data with nested children
php artisan scout:import "App\Models\ParentModel"

Step 3: Querying Nested Documents

To search for parents with children matching specific criteria, use a nested query:

use Laravel\Scout\Builder;

$parents = ParentModel::search('')
    ->query(function (Builder $builder) {
        $builder->nested('children', function ($query) {
            $query->match('children.name', 'John');
        });
    })
    ->get();

Option 2: Parent-Child Relationships (Best for Independent Updates)

If you need to update children documents without reindexing the entire parent, or if you have a huge number of children per parent, use Elasticsearch's join data type to establish a parent-child relationship (both types live in a single index).

Step 1: Define the Parent Model with Join Mapping

// app/Models/ParentModel.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;

class ParentModel extends Model
{
    use Searchable;

    protected $table = 'parents';

    // Single index for both parents and children
    public function searchableAs()
    {
        return 'family_index';
    }

    public function toSearchableArray()
    {
        $array = $this->toArray();
        // Mark this as a parent document in the join field
        $array['family_relation'] = [
            'name' => 'parent',
        ];
        return $array;
    }

    public function getMapping()
    {
        return [
            'properties' => [
                'id' => ['type' => 'integer'],
                'name' => ['type' => 'text'],
                // Define the join relationship
                'family_relation' => [
                    'type' => 'join',
                    'relations' => [
                        'parent' => 'children' // parent = parent type, children = child type
                    ]
                ]
            ]
        ];
    }
}

Step 2: Define the Children Model with Parent Reference

// app/Models/Children.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;

class Children extends Model
{
    use Searchable;

    protected $table = 'childrens';

    // Use the same index as the parent
    public function searchableAs()
    {
        return 'family_index';
    }

    public function toSearchableArray()
    {
        $array = $this->toArray();
        // Mark this as a child document and link to its parent
        $array['family_relation'] = [
            'name' => 'children',
            'parent' => (string) $this->parent_id // Must be a string to match Elasticsearch's _id
        ];
        return $array;
    }
}

Step 3: Create the Index and Import Data

  1. First create the index with the join mapping by importing the parent model:
php artisan scout:import "App\Models\ParentModel"
  1. Then import the children documents:
php artisan scout:import "App\Models\Children"

Step 4: Querying Parent-Child Relationships

  • Find parents that have matching children:
$parents = ParentModel::search('')
    ->query(function ($builder) {
        $builder->hasChild('children', function ($query) {
            $query->match('name', 'John');
        });
    })
    ->get();
  • Find children that belong to a matching parent:
$children = Children::search('')
    ->query(function ($builder) {
        $builder->hasParent('parent', function ($query) {
            $query->match('name', 'Alice');
        });
    })
    ->get();

Key Notes

  • Nested Documents: Easier to query, but updating a child requires reindexing the entire parent. Best for small, tightly coupled datasets.
  • Parent-Child Relationships: More flexible for independent updates, but queries are slightly more complex and have a small performance overhead. Best for large datasets with frequent child updates.

Test both approaches with your specific use case to see which works better!

内容的提问来源于stack exchange,提问作者Jasmel Pc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:49:47