PHPackages                             jarir-ahmed/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. jarir-ahmed/search

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

jarir-ahmed/search
==================

A unified, framework-agnostic search abstraction for PHP with Elasticsearch and in-memory engines.

v1.0.1(1mo ago)018↓87.5%1MITPHPPHP &gt;=7.4CI passing

Since Jun 6Pushed 1mo agoCompare

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

READMEChangelogDependencies (1)Versions (3)Used By (1)

search
======

[](#search)

[![CI](https://github.com/jarir2020/jarir-ahmed-search/actions/workflows/ci.yml/badge.svg)](https://github.com/jarir2020/jarir-ahmed-search/actions/workflows/ci.yml)

A unified, framework-agnostic **search abstraction** for PHP. Write your queries once and run them against **Elasticsearch / OpenSearch** in production or a dependency-free **in-memory**engine for tests and small datasets — same API, same results shape.

Features
--------

[](#features)

- One `SearchEngineInterface`: `index`, `bulk`, `delete`, `clear`, `search` — swap backends without touching call sites.
- Engines for **Elasticsearch/OpenSearch, Solr, Algolia, Meilisearch, Typesense**, a **database** (PDO) engine, an **in-memory** engine, and a **vector/semantic** engine.
- Fluent `Query` builder shared by every engine: term, field boosts, exact filters, fuzziness, sorting, pagination, and embeddings for semantic search.
- HTTP engines talk through a pluggable `TransportInterface`, so they're fully unit-testable without a live server.

Backends
--------

[](#backends)

EngineClassNotesIn-memory`Engines\InMemoryEngine`Tokenized scoring, fuzzy (Levenshtein), substring, filters. No deps.Elasticsearch / OpenSearch`Engines\ElasticsearchEngine`Query DSL via transport.Solr`Engines\SolrEngine`JSON Request API + edismax.Algolia`Engines\AlgoliaEngine`Transport carries app-id / API-key headers.Meilisearch`Engines\MeilisearchEngine`Bearer-token transport.Typesense`Engines\TypesenseEngine`Needs `query_by` fields.Database (PDO)`Engines\DatabaseEngine`Portable LIKE-based FTS, self-creates its table.Vector / semantic`Engines\VectorEngine`Cosine similarity over caller-supplied embeddings.Per-engine setup (transports, credentials, index configuration) is documented in [docs/engines.md](docs/engines.md).

Requirements
------------

[](#requirements)

- PHP &gt;= 7.4, `ext-json`
- `ext-curl` only if you use the bundled `CurlTransport`

Install
-------

[](#install)

```
composer require jarir-ahmed/search
```

Quick start (in-memory)
-----------------------

[](#quick-start-in-memory)

```
use JarirAhmed\Search\SearchManager;
use JarirAhmed\Search\Engines\InMemoryEngine;
use JarirAhmed\Search\Query;

$search = new SearchManager(new InMemoryEngine());

$search->bulk([
    '1' => ['title' => 'Blue Running Shoes', 'category' => 'footwear', 'price' => 80],
    '2' => ['title' => 'Red Leather Boots',  'category' => 'footwear', 'price' => 150],
]);

// Simple string search
$result = $search->search('blue');
$result->ids();        // ['1']
$result->total();      // 1
$result->documents();  // [['title' => 'Blue Running Shoes', ...]]

// Rich query: boosts, fuzziness, filter, sort, pagination
$result = $search->search(
    Query::create('runing')                 // typo
        ->fields(['title' => 2.0])
        ->fuzziness(1)                       // matches "running"
        ->filter('category', 'footwear')
        ->sortBy('price', 'asc')
        ->from(0)->size(20)
);
```

Elasticsearch / OpenSearch
--------------------------

[](#elasticsearch--opensearch)

```
use JarirAhmed\Search\SearchManager;
use JarirAhmed\Search\Engines\ElasticsearchEngine;
use JarirAhmed\Search\Transport\CurlTransport;

$transport = new CurlTransport('http://localhost:9200', [
    'username' => 'elastic',
    'password' => 'changeme',
    // or 'apiKey' => '...'
    'timeout'  => 5,
]);

$search = new SearchManager(new ElasticsearchEngine($transport, 'products'));

$search->index('1', ['title' => 'Blue Running Shoes', 'category' => 'footwear']);
$result = $search->search(Query::create('blue')->fields(['title' => 2.0]));
```

The engine talks to ES through a `TransportInterface`. Swap in your own (Guzzle, PSR-18, a mock) by implementing `request(string $method, string $path, ?array $body): array`.

> Note: `term` filters and `sort` assume the field is keyword/numeric in your ES mapping.

Solr, Algolia, Meilisearch and Typesense work the same way — construct the engine with a transport and an index/collection name. Configure service auth on the transport, e.g.:

```
new CurlTransport('https://APPID-dsn.algolia.net', ['headers' => [
    'X-Algolia-Application-Id: APPID',
    'X-Algolia-API-Key: KEY',
]]);                                   // Algolia
new CurlTransport('http://127.0.0.1:7700', ['headers' => ['Authorization: Bearer KEY']]);   // Meilisearch
new CurlTransport('http://127.0.0.1:8108', ['headers' => ['X-TYPESENSE-API-KEY: KEY']]);    // Typesense
```

Database engine (no search server)
----------------------------------

[](#database-engine-no-search-server)

```
use JarirAhmed\Search\Engines\DatabaseEngine;

$engine = new DatabaseEngine(new PDO('sqlite:search.db')); // or MySQL / Postgres
$engine->index('1', ['title' => 'Blue Shoes', 'category' => 'footwear']);
$hits = $engine->search(Query::create('blue')->filter('category', 'footwear'));
```

Semantic / vector search
------------------------

[](#semantic--vector-search)

Supply embeddings from any model; ranking is by cosine similarity — no external service.

```
use JarirAhmed\Search\Engines\VectorEngine;

$engine = new VectorEngine(); // documents carry an "embedding" field
$engine->index('cat', ['label' => 'cat', 'embedding' => [1.0, 0.0, 0.0]]);
$engine->index('car', ['label' => 'car', 'embedding' => [0.0, 0.0, 1.0]]);

$result = $engine->search(Query::create('')->vector([0.95, 0.05, 0.0]));
$result->ids(); // ['cat', ...] ranked by similarity
```

Query reference
---------------

[](#query-reference)

MethodDescription`Query::create($term)`New query for a search string (empty = match all).`->fields(['title' => 2.0, 'body'])`Restrict + boost searched fields.`->filter($field, $value)`Exact filter (ANDed). Matches array membership too.`->fuzziness($n)`Max edit distance for approximate matches.`-&gt;sortBy($field, 'asc''desc')``->from($n)` / `->size($n)`Pagination.`search()` returns a `SearchResult` (iterable, countable): `hits()`, `ids()`, `documents()`, `total()`, `isEmpty()`. Each `Hit` has `id`, `score`, `source`.

Testing
-------

[](#testing)

```
composer install
composer test
```

The suite covers the in-memory engine end-to-end and the Elasticsearch engine via a fake transport (no server required).

License
-------

[](#license)

MIT

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance90

Actively maintained with recent releases

Popularity8

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity35

Early-stage or recently created project

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 ~0 days

Total

2

Last Release

49d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/20700f34ff813055154e843bbdbe04d33320c1e6a81bbb3301cad67cb8350fd3?d=identicon)[jarircse16](/maintainers/jarircse16)

---

Tags

searchelasticsearchopensearchfuzzyIn Memoryfull-text

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/jarir-ahmed-search/health.svg)

```
[![Health](https://phpackages.com/badges/jarir-ahmed-search/health.svg)](https://phpackages.com/packages/jarir-ahmed-search)
```

###  Alternatives

[elasticsearch/elasticsearch

PHP Client for Elasticsearch

5.3k187.3M1.1k](/packages/elasticsearch-elasticsearch)[opensearch-project/opensearch-php

PHP Client for OpenSearch

15728.5M120](/packages/opensearch-project-opensearch-php)[jolicode/elastically

Opinionated Elastica based framework to bootstrap PHP and Elasticsearch implementations.

2591.8M1](/packages/jolicode-elastically)[jsq/amazon-es-php

Support for using IAM authentication with the official Elasticsearch PHP client

9311.4M13](/packages/jsq-amazon-es-php)[netgen/query-translator

Query Translator is a search query translator with AST representation

2042.1M8](/packages/netgen-query-translator)[spatie/elasticsearch-query-builder

Build and execute an Elasticsearch search query using a fluent PHP API

182775.6k8](/packages/spatie-elasticsearch-query-builder)

PHPackages © 2026

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