Collection 에서 풀 텍스트 검색 구현 팁

특정 디렉토리에 포함된 파일을 읽어서 모델을 만들고 있는 프로젝트가 있습니다.

해당 파일은 원격에 있는 컨텐츠 서버랑 rsync를 통해서 몇 분 단위로 동기화 되기 때문에, DB 테이블에 넣을 수 없고, 따라서 Eloquent도 쓸 수 없는 상황입니다.

모델에서 all(), find($id) 등의 메소드는 쉽게 구현할 수 있었습니다.
그런데, Eloquent를 사용하지 않고 검색을 어떻게 구현할까 고민하다가 아래와 같은 방법을 찾았습니다.

Eloquent가 아닌 Array 기반 Collection에서 풀 텍스트 검색에서 아래 구현의 핵심은
1) filter() 메소드를 사용한다.
2) 풀텍스트 검색 대상이 되는 Value들을 Concatenation한다.
3) str_contains() 라라벨 내장 함수를 사용한다.

정도로 요약할 수 있겠습니다.

$data = [
    [
        'title' => 'Lorem ipsum dolor sit amet',
        'description' => 'Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat'
    ],
    [
        'title' => 'Duis aute irure dolor in reprehenderit',
        'description' => 'Excepteur enim sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum'
    ]
];

// $data 배열을 이용하여 \Illuminate\Support\Collection 객체를 얻어 옵니다.
$collection = collect($data);

// 'title' 또는 'description' 값으로 Lorem 문자열을 담고 있는 Collection을 반환합니다.
// 1개가 검색됩니다.
$collection->filter(function($item) {
    return str_contains($item['title'] . $item['description'], 'Lorem'); 
});

// 'title' 또는 'description' 값으로 enim 문자열을 담고 있는 Collection을 반환합니다.
// 2개가 검색됩니다.
$collection->filter(function($item) {
    return str_contains($item['title'] . $item['description'], 'enim'); 
});

Class 컨텍스트에서 사용한다면 모델에 대략 이런 메소드로 이용하면 되지 싶습니다.

class MyModel {
    public function __construct(array $data)
    {
        $this->collection = collect($data);
    }

    public function search($keyword)
    {
        return $this->collection->filter(function($item) use ($keyword) {
            return str_contains($item['title'] . $item['description'], $keyword);
        });
    }
}

라라벨 짱~

comments powered by Disqus