PHPackages                             andydefer/inverted-index-search - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Search &amp; Filtering](/categories/search)
4. /
5. andydefer/inverted-index-search

ActiveLibrary[Search &amp; Filtering](/categories/search)

andydefer/inverted-index-search
===============================

A powerful search engine library based on Inverted Index for PHP - Full-text search, boolean queries, and expression evaluation

v0.3.14(1w ago)077↑16.7%1MITPHPPHP &gt;=8.1

Since Jul 2Pushed 1mo agoCompare

[ Source](https://github.com/andydefer/inverted-index-search)[ Packagist](https://packagist.org/packages/andydefer/inverted-index-search)[ RSS](/packages/andydefer-inverted-index-search/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (10)Versions (18)Used By (1)

InvertedIndexSearch - Documentation complète
============================================

[](#invertedindexsearch---documentation-complète)

[![PHP Version](https://camo.githubusercontent.com/7535257ca228724c93658bd52583d4e47a9bab02c356abf6e54c1d575f2151e6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e312532422d626c75652e737667)](https://php.net)[![License](https://camo.githubusercontent.com/8bb50fd2278f18fc326bf71f6e88ca8f884f72f179d3e555e20ed30157190d0d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e2e737667)](LICENSE)[![Package](https://camo.githubusercontent.com/f2e1a0797552353b2fea95db1f2d85a83a93444cd80eabf1eac1377b16921a58/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7061636b6167652d616e64796465666572253246696e7665727465642d2d696e6465782d2d7365617263682d626c7565)](https://packagist.org/packages/andydefer/inverted-index-search)

📖 Table des matières
--------------------

[](#-table-des-matières)

1. [Introduction](#introduction)
2. [Installation](#installation)
3. [Architecture](#architecture)
4. [Composants principaux](#composants-principaux)
    - [InvertedIndexSearchService](#invertedindexsearchservice)
    - [InvertedIndexQueryBuilder](#invertedindexquerybuilder)
    - [InvertedIndexExpressionEvaluator](#invertedindexexpressionevaluator)
5. [Opérateurs booléens](#op%C3%A9rateurs-bool%C3%A9ens)
6. [Cas d'usage réels](#cas-dusage-r%C3%A9els)
7. [Performance](#performance)
8. [API Reference](#api-reference)

---

Introduction
------------

[](#introduction)

**InvertedIndexSearch** est une bibliothèque PHP qui étend les capacités de l'index inversé d'AlgoKIT en fournissant un moteur de recherche complet avec opérateurs booléens. Elle permet d'effectuer des recherches plein texte complexes avec une syntaxe intuitive et des performances optimales.

### Philosophie

[](#philosophie)

ProblèmeSolution classiqueSolution InvertedIndexSearchRecherche plein texteScanner tous les documents (lent)Index inversé (O(1) par terme)Requêtes booléennesImplémentation manuelleOpérateurs AND, OR, NOT, XORRequêtes complexesConstruction manuelle d'expressionsQueryBuilder fluentExpressions imbriquéesParsing complexeÉvaluateur avec support des parenthèses### Les 3 composants clés

[](#les-3-composants-clés)

ComposantRôleUtilisation**SearchService**API principale de rechercheMéthodes pratiques (and, or, not, xor)**QueryBuilder**Construction fluent de requêtesConditions et groupes imbriqués**ExpressionEvaluator**Évaluation d'expressionsParsing et évaluation booléenne---

Installation
------------

[](#installation)

```
composer require andydefer/inverted-index-search
```

### Prérequis

[](#prérequis)

- PHP 8.1 ou supérieur
- `andydefer/algo-kit` ^0.4.0 (inclus automatiquement)
- `andydefer/domain-structures` (inclus automatiquement)

---

Architecture
------------

[](#architecture)

### Dépendances

[](#dépendances)

```
InvertedIndexSearch
    ├── AlgoKIT (InvertedIndex)
    ├── DomainStructures (StringTypedCollection)
    └── StorageKit (StorageInterface)

```

### Structure des composants

[](#structure-des-composants)

```
InvertedIndexSearchService (API principale)
    ├── and() / or() / not() / xor()
    ├── expression()
    ├── andWithLimit() / orWithLimit()
    └── query() → QueryBuilder
         ↓
InvertedIndexQueryBuilder (Fluent)
    ├── where() / orWhere() / whereNot()
    ├── whereGroup() / orWhereGroup()
    ├── get() / reset() / toExpression()
         ↓
InvertedIndexExpressionEvaluator (Évaluateur)
    ├── tokenize()
    ├── shuntingYard() → RPN
    └── evaluateRPN()

```

---

Composants principaux
---------------------

[](#composants-principaux)

### InvertedIndexSearchService

[](#invertedindexsearchservice)

Service principal offrant une API intuitive pour les recherches booléennes.

**Méthodes principales :**

MéthodeDescriptionExemple`and(array $tokens)`Tous les tokens doivent être présents`$search->and(['php', 'laravel'])``or(array $tokens)`Au moins un token doit être présent`$search->or(['php', 'python'])``not(string $include, string $exclude)`Inclure un token, exclure un autre`$search->not('php', 'python')``xor(string $term1, string $term2)`Exactement un des deux tokens`$search->xor('php', 'python')``expression(string $expr)`Expression booléenne complexe`$search->expression('(php OR python) AND laravel')``andWithLimit(array $tokens, int $limit)`AND avec limite`$search->andWithLimit(['php'], 10)``orWithLimit(array $tokens, int $limit)`OR avec limite`$search->orWithLimit(['php'], 10)``query()`Retourne le QueryBuilder`$search->query()->where('php')->get()`**Exemple d'utilisation :**

```
use AndyDefer\AlgoKIT\Algorithms\InvertedIndex;
use AndyDefer\InvertedIndexSearch\Services\InvertedIndexSearchService;
use AndyDefer\InvertedIndexSearch\Services\InvertedIndexExpressionEvaluator;
use AndyDefer\StorageKit\Storage\MemoryStorage;

$storage = new MemoryStorage();
$index = new InvertedIndex($storage, 'documents');
$evaluator = new InvertedIndexExpressionEvaluator($index);
$search = new InvertedIndexSearchService($index, $evaluator);

// Indexation des documents
$documents = [
    ['id' => 'doc1', 'tokens' => ['php', 'laravel', 'web']],
    ['id' => 'doc2', 'tokens' => ['php', 'python', 'data']],
    ['id' => 'doc3', 'tokens' => ['php', 'laravel', 'vuejs']],
    ['id' => 'doc4', 'tokens' => ['python', 'django', 'web']],
];

foreach ($documents as $doc) {
    $index->add(InvertedIndexRecord::from([
        'document_id' => $doc['id'],
        'tokens' => $doc['tokens'],
    ]));
}

// Recherches
$results1 = $search->and(['php', 'laravel']);
// → doc1, doc3

$results2 = $search->or(['php', 'python']);
// → doc1, doc2, doc3, doc4

$results3 = $search->not('php', 'python');
// → doc1, doc3

$results4 = $search->expression('(php AND laravel) OR (python AND django)');
// → doc1, doc3, doc4
```

### InvertedIndexQueryBuilder

[](#invertedindexquerybuilder)

Constructeur fluent pour des requêtes complexes.

**Méthodes :**

MéthodeDescriptionExemple`where(string $token)`Condition AND`->where('php')``orWhere(string $token)`Condition OR`->orWhere('python')``whereNot(string $token)`Exclusion`->whereNot('java')``whereGroup(callable $callback)`Groupe AND`->whereGroup(fn($q) => $q->where('laravel')->orWhere('vuejs'))``orWhereGroup(callable $callback)`Groupe OR`->orWhereGroup(fn($q) => $q->where('php')->where('laravel'))``get()`Exécute la requête`->get()``reset()`Réinitialise le builder`->reset()``toExpression()`Génère l'expression`->toExpression()`**Exemple d'utilisation :**

```
// Requête : php AND (laravel OR vuejs) AND NOT python
$results = $search->query()
    ->where('php')
    ->whereGroup(function($q) {
        $q->where('laravel')
          ->orWhere('vuejs');
    })
    ->whereNot('python')
    ->get();

// Construction dynamique
$builder = $search->query();

if ($mustHave) {
    foreach ($mustHave as $token) {
        $builder->where($token);
    }
}

if ($shouldHave) {
    $builder->whereGroup(function($q) use ($shouldHave) {
        foreach ($shouldHave as $token) {
            $q->orWhere($token);
        }
    });
}

$results = $builder->get();
```

### InvertedIndexExpressionEvaluator

[](#invertedindexexpressionevaluator)

Évaluateur d'expressions booléennes avec support des parenthèses.

**Syntaxe supportée :**

OpérateurDescriptionPrioritéExemple`NOT`Négation (unaire)4`NOT python``XOR`Ou exclusif3`php XOR python``AND`Et logique2`php AND laravel``OR`Ou logique1`php OR python``()`Regroupement-`(php OR python) AND laravel`**Exemple d'utilisation :**

```
// Expression simple
$results = $evaluator->evaluate('php AND laravel');

// Expression avec NOT
$results = $evaluator->evaluate('php AND (NOT python)');

// Expression complexe imbriquée
$results = $evaluator->evaluate('(php AND laravel) OR (python AND django)');

// Expression avec plusieurs niveaux
$results = $evaluator->evaluate('php AND (laravel OR vuejs) AND (NOT python)');
```

---

Opérateurs booléens
-------------------

[](#opérateurs-booléens)

### AND (Et logique)

[](#and-et-logique)

Documents contenant tous les tokens.

```
// Syntaxe directe
$results = $search->and(['php', 'laravel']);

// Via expression
$results = $search->expression('php AND laravel');

// Via QueryBuilder
$results = $search->query()->where('php')->where('laravel')->get();
```

### OR (Ou logique)

[](#or-ou-logique)

Documents contenant au moins un token.

```
// Syntaxe directe
$results = $search->or(['php', 'python']);

// Via expression
$results = $search->expression('php OR python');

// Via QueryBuilder
$results = $search->query()->where('php')->orWhere('python')->get();
```

### NOT (Négation)

[](#not-négation)

Documents contenant le premier token mais pas le second.

```
// Syntaxe directe
$results = $search->not('php', 'python');

// Via expression
$results = $search->expression('php AND (NOT python)');

// Via QueryBuilder
$results = $search->query()->where('php')->whereNot('python')->get();
```

### XOR (Ou exclusif)

[](#xor-ou-exclusif)

Documents contenant exactement un des deux tokens.

```
// Syntaxe directe
$results = $search->xor('php', 'python');

// Via expression
$results = $search->expression('php XOR python');

// Via QueryBuilder (via expression)
$results = $search->query()->expression('php XOR python')->get();
```

---

Cas d'usage réels
-----------------

[](#cas-dusage-réels)

### 1. Moteur de recherche de blog

[](#1-moteur-de-recherche-de-blog)

**Problème :** Implémenter un moteur de recherche d'articles avec filtres par tags, catégories et exclusions.

```
class BlogSearch
{
    private InvertedIndexSearchService $search;

    public function searchArticles(array $criteria): array
    {
        $builder = $this->search->query();

        // Tags obligatoires
        if (!empty($criteria['tags'])) {
            foreach ($criteria['tags'] as $tag) {
                $builder->where($tag);
            }
        }

        // Catégories (au moins une)
        if (!empty($criteria['categories'])) {
            $builder->whereGroup(function($q) use ($criteria) {
                foreach ($criteria['categories'] as $category) {
                    $q->orWhere($category);
                }
            });
        }

        // Exclusions
        if (!empty($criteria['exclude'])) {
            foreach ($criteria['exclude'] as $exclude) {
                $builder->whereNot($exclude);
            }
        }

        return $builder->get()->toArray();
    }
}

// Utilisation
$articles = $blogSearch->searchArticles([
    'tags' => ['php', 'laravel'],
    'categories' => ['web', 'api'],
    'exclude' => ['deprecated'],
]);
```

### 2. Recherche de produits e-commerce

[](#2-recherche-de-produits-e-commerce)

**Problème :** Rechercher des produits avec filtres multiples et alternatives.

```
class ProductSearch
{
    private InvertedIndexSearchService $search;

    public function search(array $filters): array
    {
        $builder = $this->search->query();

        // Marques (AND)
        if (!empty($filters['brands'])) {
            foreach ($filters['brands'] as $brand) {
                $builder->where($brand);
            }
        }

        // Couleurs (OR)
        if (!empty($filters['colors'])) {
            $builder->whereGroup(function($q) use ($filters) {
                foreach ($filters['colors'] as $color) {
                    $q->orWhere($color);
                }
            });
        }

        // Prix (facultatif)
        if (isset($filters['price_range'])) {
            $builder->where($filters['price_range']);
        }

        return $builder->get()->toArray();
    }
}

// Utilisation
$products = $productSearch->search([
    'brands' => ['nike', 'adidas'],
    'colors' => ['red', 'blue', 'black'],
    'price_range' => 'premium',
]);
```

### 3. Analyse de logs avec filtres

[](#3-analyse-de-logs-avec-filtres)

**Problème :** Analyser des logs d'application avec des filtres complexes.

```
class LogAnalyzer
{
    private InvertedIndexSearchService $search;

    public function analyzeLogs(array $logs): array
    {
        $expression = 'error OR (warning AND php) NOT (debug OR trace)';

        $results = $this->search->expression($expression);

        $stats = [
            'total' => count($logs),
            'matching' => $results->count(),
            'log_ids' => $results->toArray(),
        ];

        return $stats;
    }
}

// Utilisation
$analyzer = new LogAnalyzer($search);
$stats = $analyzer->analyzeLogs($logs);
```

### 4. API de recherche dynamique

[](#4-api-de-recherche-dynamique)

**Problème :** Exposer une API de recherche où les utilisateurs peuvent utiliser des opérateurs booléens.

```
class SearchAPI
{
    private InvertedIndexSearchService $search;

    public function search(Request $request): JsonResponse
    {
        $query = $request->get('q');
        $limit = (int) $request->get('limit', 10);

        try {
            // L'utilisateur peut utiliser des opérateurs avancés
            $results = $this->search->expression($query);
            $limited = $results->take($limit);

            return response()->json([
                'success' => true,
                'results' => $limited->toArray(),
                'total' => $results->count(),
                'limit' => $limit,
            ]);
        } catch (InvalidArgumentException $e) {
            return response()->json([
                'success' => false,
                'error' => 'Invalid search expression',
                'message' => $e->getMessage(),
            ], 400);
        }
    }
}

// Requêtes API acceptées
// GET /search?q=php AND laravel
// GET /search?q=(php OR python) AND web
// GET /search?q=php AND (NOT java)
// GET /search?q=php AND (laravel OR vuejs) NOT python
```

### 5. Système de recommandation de tags

[](#5-système-de-recommandation-de-tags)

**Problème :** Recommander des tags pertinents basés sur une combinaison de tags existants.

```
class TagRecommender
{
    private InvertedIndexSearchService $search;

    public function recommendTags(array $existingTags, int $limit = 5): array
    {
        $builder = $this->search->query();

        // Tags existants
        foreach ($existingTags as $tag) {
            $builder->where($tag);
        }

        $results = $builder->get();

        // Extraire les tags associés
        $relatedTags = [];
        foreach ($results as $docId) {
            $doc = $this->getDocument($docId);
            $relatedTags = array_merge($relatedTags, $doc['tags']);
        }

        // Compter et trier les tags
        $counts = array_count_values($relatedTags);
        arsort($counts);

        // Filtrer les tags existants
        $recommended = array_diff(array_keys($counts), $existingTags);

        return array_slice($recommended, 0, $limit);
    }
}

// Utilisation
$recommendations = $recommender->recommendTags(['php', 'laravel']);
// → ['web', 'api', 'eloquent', 'vuejs']
```

---

Performance
-----------

[](#performance)

### Complexité algorithmique

[](#complexité-algorithmique)

OpérationComplexitéDétailsAND (2 tokens)O(a + b)Intersection de deux ensemblesAND (n tokens)O(n × m)Intersection séquentielleOR (n tokens)O(n × m)Union et déduplicationNOTO(a + b)Différence d'ensemblesXORO(a + b)Différences symétriquesExpressionO(n × m)Dépend de la complexité### Optimisations

[](#optimisations)

- **Recherche en cache** : Chaque token est recherché une seule fois
- **Opérations natives** : Utilisation des fonctions PHP optimisées en C
- **Lazy loading** : QueryBuilder instancié à la demande
- **Collections typées** : `StringTypedCollection` pour des opérations efficaces
- **Pas de duplication** : Les résultats sont dédupliqués automatiquement

### Comparatif

[](#comparatif)

StructureMémoirePerformancePrécisionInvertedIndexSearchMoyenneRapide (O(1) par terme)100%Recherche naïveÉlevéeLent (O(n))100%Base de données SQLÉlevéeMoyen (indexes)100%---

API Reference
-------------

[](#api-reference)

### Services

[](#services)

- [InvertedIndexSearchService](docs/api-reference/services/search-service.md) - Service principal de recherche
- [InvertedIndexQueryBuilder](docs/api-reference/services/query-builder.md) - Constructeur fluent
- [InvertedIndexExpressionEvaluator](docs/api-reference/services/expression-evaluator.md) - Évaluateur d'expressions

### Interfaces

[](#interfaces)

- `InvertedIndexSearchServiceInterface` - Interface du service de recherche
- `InvertedIndexQueryBuilderInterface` - Interface du QueryBuilder
- `InvertedIndexExpressionEvaluatorInterface` - Interface de l'évaluateur

### Enums

[](#enums)

- `InvertedIndexOperator` - Opérateurs booléens (AND, OR, NOT, XOR)

### Collections

[](#collections)

- `StringTypedCollection` - Collection de chaînes de caractères

---

License
-------

[](#license)

MIT © [Andy Defer](https://github.com/andydefer)

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance94

Actively maintained with recent releases

Popularity13

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity41

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

17

Last Release

12d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/2170ec3fbad9eb4b002661ab4f58b1cc374eae4293b92904c6a74bc2818bd570?d=identicon)[andydefer](/maintainers/andydefer)

---

Top Contributors

[![andydefer](https://avatars.githubusercontent.com/u/124321745?v=4)](https://github.com/andydefer "andydefer (4 commits)")

###  Code Quality

TestsPHPUnit

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/andydefer-inverted-index-search/health.svg)

```
[![Health](https://phpackages.com/badges/andydefer-inverted-index-search/health.svg)](https://phpackages.com/packages/andydefer-inverted-index-search)
```

###  Alternatives

[netgen/query-translator

Query Translator is a search query translator with AST representation

2062.1M9](/packages/netgen-query-translator)[fran6co/phptrie

PHP Trie implementation

3418.9k](/packages/fran6co-phptrie)[imarc/google-site-search

A PHP Interface to the Google Custom Search API

3011.6k](/packages/imarc-google-site-search)[dialekt/dialekt

A boolean expression DSL.

173.8k](/packages/dialekt-dialekt)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
