diszo2009/lucene-search-bundle
Installation
composer require egeloen/lucene-search-bundle
Add to config/bundles.php:
return [
// ...
Egeloen\LuceneSearchBundle\EgeloenLuceneSearchBundle::class => ['all' => true],
];
Configuration
Define indexes in config/packages/egeloen_lucene_search.yaml:
egeloen_lucene_search:
indexes:
default:
path: '%kernel.project_dir%/var/lucene/default'
fields:
- { name: 'title', type: 'text' }
- { name: 'content', type: 'text' }
- { name: 'created_at', type: 'date' }
First Use Case
Index a model (e.g., Article):
use Egeloen\LuceneSearchBundle\Indexer\IndexerInterface;
class ArticleService {
public function __construct(private IndexerInterface $indexer) {}
public function indexArticle(Article $article) {
$this->indexer->index('default', $article->toArray());
}
}
Query the index:
use Egeloen\LuceneSearchBundle\Searcher\SearcherInterface;
class ArticleSearch {
public function __construct(private SearcherInterface $searcher) {}
public function search(string $query) {
return $this->searcher->search('default', $query);
}
}
Indexing Strategy
IndexerInterface::index() for single documents or indexMany() for bulk operations.postPersist, postUpdate):
// src/EventListener/ArticleIndexListener.php
use Egeloen\LuceneSearchBundle\Indexer\IndexerInterface;
class ArticleIndexListener {
public function __construct(private IndexerInterface $indexer) {}
public function postPersist(Article $article) {
$this->indexer->index('default', $article->toArray());
}
}
Querying Patterns
$results = $this->searcher->search('default', 'lucene symfony');
$query = 'title:"Symfony" AND (content:lucene OR content:search)';
$results = $this->searcher->search('default', $query);
$results = $this->searcher->search('default', $query, 0, 10); // offset, limit
Integration with Laravel Controllers
use Egeloen\LuceneSearchBundle\Searcher\SearcherInterface;
class ArticleController extends Controller {
public function __construct(private SearcherInterface $searcher) {}
public function search(Request $request) {
$query = $request->input('q');
$results = $this->searcher->search('default', $query);
return view('articles.search', compact('results'));
}
}
Hybrid Search (Database + Lucene)
// Pseudocode for hybrid search
$luceneResults = $this->searcher->search('default', $query);
$dbResults = Article::where('title', 'like', "%{$query}%")->get();
$mergedResults = $luceneResults->merge($dbResults);
Index Path Permissions
var/lucene/) is writable by the web server user:
chmod -R 775 var/lucene/
storage/logs/dev.log) for Permission denied errors.Field Mapping Mismatches
config/packages/egeloen_lucene_search.yaml match your data.date field in config won’t work with a string value in your data.Lucene Index Corruption
rm -rf var/lucene/default/
Case Sensitivity
TextField with lowercase analyzer for case-insensitive searches:
fields:
- { name: 'title', type: 'text', analyzer: 'lowercase' }
Memory Usage
indexMany().Query Debugging
$query = 'title:"Symfony"^2 content:lucene';
// ^2 boosts the title field
Logging
config/packages/dev/egeloen_lucene_search.yaml:
egeloen_lucene_search:
debug: true
Configuration Overrides
config/packages/prod/egeloen_lucene_search.yaml):
egeloen_lucene_search:
indexes:
default:
path: '%kernel.project_dir%/var/lucene/prod_default'
Custom Analyzers
// src/Analyzer/CustomAnalyzer.php
use Egeloen\LuceneSearchBundle\Analyzer\AnalyzerInterface;
class CustomAnalyzer implements AnalyzerInterface {
public function analyze(string $text): array {
// Custom logic (e.g., stemming)
return [$text]; // Simplified
}
}
egeloen_lucene_search:
analyzers:
custom:
class: App\Analyzer\CustomAnalyzer
Event Listeners
// src/EventListener/LuceneEventListener.php
use Egeloen\LuceneSearchBundle\Event\IndexEvent;
class LuceneEventListener {
public function onIndex(IndexEvent $event) {
// Modify document before indexing
$event->setDocument($event->getDocument()->merge(['custom_field' => 'value']));
}
}
services.yaml:
services:
App\EventListener\LuceneEventListener:
tags:
- { name: kernel.event_listener, event: egeloen_lucene.index, method: onIndex }
Custom Search Results
class ArticleSearchResult {
public static function fromLuceneResult(array $result): self {
return new self(
id: $result['id'],
title: $result['title'],
score: $result['score']
);
}
}
How can I help you explore Laravel packages today?