Releases: PHP-CMSIG/search
Release 0.6.0 (2024-12-27)
Full Changelog | Which Search Engines do you use and why? | Are you working with SEAL? Let me know!
Introduce New Logo 🎉
created by Meine Wilma
Introduce PHP CMS-IG 🏗️
What did begin as the schranz-search project, a research around different search engines. Goes forward as a cooperation between different Content Management System. SEAL – The Search Engine Absraction Layer for PHP is now under the PHP-CMSIG organisation, read more about the organisation here. We moved also to a new namespace to represent this new organisation and cooperation.
To upgrade use search and replace also have a look at the .examples changes to better understand the upgrade.
-
Package names:
schranz-search/seal
->cmsig/seal
schranz-search/seal-...-adapter
->cmsig/seal-...-adapter
schranz-search/laravel-package
->cmsig/seal-laravel-package
schranz-search/mezzio-module
->cmsig/seal-mezzio-module
schranz-search/spiral-bridge
->cmsig/seal-spiral-bridge
schranz-search/yii-module
->cmsig/seal-yii-module
schranz-search/symfony-bundle
->cmsig/seal-symfony-bundle
-
Namespaces:
Schranz\Search\SEAL
->CmsIg\Seal\
Schranz\Search\Integration
->CmsIg\Seal\Integration
-
Config Files:
schranz_search.*
->cmsig_seal.*
-
Config, Service names, Tagged Services:
schranz_search.*
->cmsig_seal.*
-
Commands:
schranz:search:*
->cmsig:seal:*
-
Spiral Integration Changes:
SearchBootloader
->SealBootloader
SearchConfig
->SealConfig
seal.php
->cmsig_seal.php
BC Breaks
- Move SEAL to CMS-IG namespace (BC Break) (#458) (@alexander-schranz)
- Introducing partial reindexes (BC Break) (#460) (@Toflar)
- Remove support for search multi Indexes by once (BC Break) (#451) (@alexander-schranz)
- Add option to control bulk size for reindex commands (BC Break) (#434) (@alexander-schranz)
Changes
- Update elasticsearch docker image from 8.15.3 to 8.17.0 (#469) (@alexander-schranz)
- Refix phpstan issues in spiral integration and add missing docs for reindex opitons (#468) (@alexander-schranz)
- Fix CI issues checking out old commits (#467) (@alexander-schranz)
- Fix phpstan issues in spiral integration (#466) (@alexander-schranz)
- Make sure identifiers are empty (#465) (@Toflar)
- Introducing partial reindexes 🎉 (BC Break) (#460) (@Toflar)
- Move Mono Repo hint to the top of the sub readme files (#464) (@alexander-schranz)
- Update Loupe to 0.8 (#461) (@alexander-schranz)
- Add cmsig/seal packages replaces schranz-search packages (#459) (@alexander-schranz)
- Move SEAL to CMS-IG namespace (BC Break) (#458) (@alexander-schranz)
- Update dependencies and docker image versions and ignore composer.lock file from stats diff (#455) (@alexander-schranz)
- Add Windows support for creating search adapters (#452) (@zoglo)
- Add tests for DSN parsing in AdapterFactory (#454) (@alexander-schranz)
- Add docs about new SearchBuilder for single index (#453) (@alexander-schranz)
- Remove support for search multi Indexes by once (BC Break) (#451) (@alexander-schranz)
- Add NotInCondition Filter 🎉 (#448) (@ToshY)
- Update Elasticsearch, Redisearch, Typesense docker compose files to latest versions (#449) (@alexander-schranz)
- Add InCondition Filter 🎉 (#447) (@alexander-schranz)
- Fix typos in AndCondition and OrCondition and Logo Creator, add hint about Algolia AndCondition (#443) (@alexander-schranz)
- Add creator hint to logo and fix favicon (#442) (@alexander-schranz)
- Add documentation about AndCondtion and OrCondition filters (#441) (@alexander-schranz)
- Add new logo for SEAL by Meine Wilma 🚀 🎉 (#440) (@alexander-schranz)
- Upgrade tooling dependencies (#439) (@alexander-schranz)
- Make And and OrConditions readonly (#438) (@alexander-schranz)
- Add support for Nested Conditions via AndCondition and OrCondition 🎉 (#433) (@Toflar)
- Fix yii integration tests (#437) (@alexander-schranz)
- Fix abstract bulk test (#436) (@alexander-schranz)
- Move bulk method from own Interface to IndexerInterface (#435) (@alexander-schranz)
- Add option to control bulk size for reindex commands 🎉 (BC Break) (#434) (@alexander-schranz)
- Add bulk operation for Engine and Indexers and use it for reindex operation 🎉 (#430) (@alexander-schranz)
- Improve algolia cleanup script to retry deletion (#429) (@alexander-schranz)
- Add stricter validation for field names (#427) (@alexander-schranz)
- Prepare 0.6 branch (#425) (@alexander-schranz)
Release 0.5.0 (2024-09-24)
- Add GeoBoundingBoxCondition 🎉 (#420) (@ker0x)
- Add GeoDistanceCondition 🎉 (#363) (@ker0x)
- Upgrade the Spiral example to latest version 🎉 (#418) (@roxblnfk)
- Upgrade loupe to version 0.7 🎉 (#421) (@alexander-schranz)
- Upgrade Algolia package to V4 🎉 (#414) (@alexander-schranz)
- Fix code style in AbstractSearcherTestCase (#424) (@alexander-schranz)
- Update different tooling dependencies to latest version (#419) (@alexander-schranz)
- Fix Yii compatibility issues with dev packages in the example project (#417) (@alexander-schranz)
- Update meilisearch image to new v1 tag (#415) (@alexander-schranz)
- Update php-cs-fixer (#413) (@alexander-schranz)
- Fix update of docs page (#412) (@alexander-schranz)
- Upgrade docker image to elasticsearch 8.15 (#411) (@alexander-schranz)
- Upgrade dependencies (#410) (@alexander-schranz)
- Upgrade redis to 7.4.0-v0 (#408) (@alexander-schranz)
- Upgrade Meilisearch to 1.9 (#406) (@alexander-schranz)
- Fix yii dependencies in example (#405) (@alexander-schranz)
- Update elasticsearch images to 8.14 (#399) (@alexander-schranz)
- Upgrade Meilisearch to 1.8 (#397) (@alexander-schranz)
- Upgrade Typesense to 26.0 (#396) (@alexander-schranz)
- Update dev tools to latest versions (#395) (@alexander-schranz)
- Update elasticsearch images (#385) (@alexander-schranz)
- Prepare 0.5 branch (#382) (@alexander-schranz)
Release 0.4.0 (2024-03-21)
- Add Support for Laravel 11 🎉 (#378) (@alexander-schranz)
- Fix Format fields with underscore in Loupe Adapter (#372) (@ker0x)
- Fix Laravel artisan key generate in composer update (#380) (@alexander-schranz)
- Fix Laravel 11 post install behaviour (#379) (@alexander-schranz)
- Prepare 0.4 branch (#377) (@alexander-schranz)
- Update Meilisearch docker images to 1.7 (#376) (@alexander-schranz)
- Fix Spiral Integration Example (#375) (@alexander-schranz)
- Upgrade all dependencies to latest versions (#374) (@alexander-schranz)
- Add nullable_type_declaration syntax union to php-cs-fixer config (#373) (@alexander-schranz)
- Add dependency injection alias for Schema class (#366) (@alexander-schranz)
- Fix Opensearch Docker compose container exited (1) appearing in Opensearch 2.12 (#369) (@alexander-schranz)
- Update dependencies (#362) (@alexander-schranz)
- Upgrade rector to 1.0 (#361) (@alexander-schranz)
- Add Blog post Scaling Elasticsearch for Fun and Profit by Jason Taylor to research docs (#360) (@alexander-schranz)
- Update Research list with paradedb (#359) (@alexander-schranz)
- Update code style with php-cs-fixer (#350) (@alexander-schranz)
- Upgrade dependencies and elasticsearch to 8.12 (#347) (@alexander-schranz)
- Update cache action for publish (#346) (@alexander-schranz)
- Upgrade python action to latest version (#345) (@alexander-schranz)
- Fix overview svg image (#344) (@alexander-schranz)
Release 0.3.1 (2024-01-19)
- Fix conflict inside the integration packages to adapters (#340) (@alexander-schranz)
- Upgrade meilisearch docker image to 1.6 (#339) (@alexander-schranz)
- Add @Toflar to Funding.yml of Loupe Adapter (#338) (@alexander-schranz)
Release 0.3.0 (2024-01-10)
Highlights
- 🔍 Support for Loupe 0.5
- 🏗️ Support for Symfony 7
- 🐘 Support for PHP 8.3
- Move from 0.2 to 0.3 branch (#337) (@alexander-schranz)
- Add Support for Loupe 0.5 (#335) (@alexander-schranz, Thx @Toflar)
- Add Symfony 7 Support for Typesense Adapter and Solr Adapter (#336) (@alexander-schranz)
- Update elasticsearch, redis and typesense docker image (#334) (@alexander-schranz)
- Allow mezzio with PHP 8.3 (#333) (@alexander-schranz)
- Add PHP 8.3 to test matrix (#323) (Thx @ker0x)
- Use phpstan.dist.neon instead of phpstan.neon file (#332) (@alexander-schranz)
- Add Support for Symfony 7 (#322) (Thx @ker0x)
- Fix documentation build (#331) (@alexander-schranz)
- Update Rector to 0.19 (#330) (@alexander-schranz)
- Add void return type for configure methods of commands (#325) (Thx @ToshY)
- Fix index_name_prefix ignored when using one schema file per index (#321) (Thx @dhirtzbruch)
- Fix combination of SearchCondition and EqualCondition in Elasticsearch and Opensearch (#314) (Thx @dhirtzbruch)
- Fix array syntax in code samples (#307) (Thx @keichinger)
- Fix missing indentation in code fence (#308) (Thx @keichinger)
- Add missing \r\n line break to test suite (#306) (@alexander-schranz)
Release 0.2.1 (2023-11-21)
Full Changelog | Documentation | Repository
- Update dependencies (#305) (@alexander-schranz)
- Update Meilisearch Docker Image to v1.5 (#304) (@alexander-schranz)
- Fix Solarium Solr PHP Client version (#303) (@alexander-schranz)
- Fix query filtering of "\r" containing values in Solrr (#302) (@alexander-schranz, Thx @thomascorthals )
- Fix escaping of string based filters in AlgoliaSearcher (#299) (@alexander-schranz)
- Fix escaping of string based filters in RedisearchSearcher (#298) (@alexander-schranz)
- Fix escaping of string based filters in SolrSearcher (#297) (@alexander-schranz)
- Fix escaping of string based filters in LoupeSearcher (#296) (@alexander-schranz)
- Fix escaping of string based filters in TypesenseSearcher (#295) (@alexander-schranz)
- Fix escaping of string based filters in MeilisearchSearcher (#294) (@alexander-schranz)
- Fix Filter Value escaping for different Adapters (#293) (@alexander-schranz)
- Fix BooleanCondition for MeilisearchSearcher (#291) (@alexander-schranz, Thx @manuelderuiter)
- Fix BooleanField mapping in SolrSchemaManager (#286) (@alexander-schranz)
- Fix BooleanCondition for RedisearchSearcher (#285) (@alexander-schranz)
- Fix ComplexElasticsearchMapping mapping test (#282) (@alexander-schranz)
- Fix ComplexOpensearchMapping mapping test (#281) (@alexander-schranz)
- Fix BooleanCondition for AlgoliaSearcher (#280) (@alexander-schranz)
- Fix BooleanCondition for TypesenseSearcher (#278) (@alexander-schranz)
- Add new test case for equal boolean field (#277) (@alexander-schranz)
- Upgrade Elasticsearch docker images to 8.11.0 (#288) (@alexander-schranz)
- Fix publish of documentation for 0.2 (#287) (@alexander-schranz)
- Bump php-cs-fixer/shim from 3.36.0 to 3.37.1 in /packages/seal (#274) (@dependabot[bot])
- Add "update: strategy: "widen" to dependabot.yml (#275) (@alexander-schranz)
- Update dependencies (#272) (@alexander-schranz)
- Add support for PHP Redis Extension ^6.0 (#271) (@alexander-schranz)
- Fix code example for SearchCondition (#270) (Thx @MDevster)
Release 0.2.0 (2023-09-29)
SEAL welcomes Loupe
A search engine based on only PHP and SQLite
An SQLite based, PHP-only fulltext search engine.
Use the new adapter with schranz-search/seal-loupe-adapter
.
Read more about Loupe project by @Toflar: https://github.com/loupe-php/loupe.
- Update dependencies (#262) (@alexander-schranz)
- Test against Redisearch 7.2.0 (#261) (@alexander-schranz)
- Test against Elasticsearch 8.10.0 (#259) (@alexander-schranz)
- Test against Meilisearch 1.4 (#260) (@alexander-schranz)
- Test against Typesense 0.25.1 (#257) (@alexander-schranz)
- Update doc version to 0.2 (#256) (@alexander-schranz)
- Add support for Loupe 0.4 version (#250) (@alexander-schranz)
- Upgrade to schranz/mono 2.0.0 (#248) (@alexander-schranz)
- Fix subtree split by use github.ref_name instead of ENV variable (#247) (@alexander-schranz)
- Fix split by use GITHUB_HEAD_REF (#246) (@alexander-schranz)
- Add conflict to doctrine/dbal < 3.6 for loupe adapter (#245) (@alexander-schranz)
- Upgrade to phpunit 10 (#244) (@alexander-schranz)
- Upgrade rector to 0.18.1 (#243) (@alexander-schranz)
- Prepare 0.2 version (#242) (@alexander-schranz)
- Add new label to Loupe (#239) (@alexander-schranz)
- Fix CI for Loupe Adapter (#238) (@alexander-schranz)
- Add support for Loupe PHP (#222) (@alexander-schranz, Thx @Toflar)
- Dependency and tooling version updates (#234) (@alexander-schranz)
- Fix issue with new redis version (#233) (@alexander-schranz)
- Fix pull request target checkout the correct commit (#231) (@alexander-schranz)
- Add check if local dependencies works like expected (#228) (@alexander-schranz)
- Fix MemorySearcher for LessThan and GreaterThan test cases (#227) (@alexander-schranz)
- Fix MemorySearcher for LessThan and GreaterThan test cases (#227) (@alexander-schranz)
- Add testing for greater and lesser than on multi values (#226) (@alexander-schranz)
- Add loupe to the research document (#221) (@alexander-schranz)
- Fix Yii framework composer lint codecept build task (#219) (@alexander-schranz)
- Add temporary fix for Yii Ci (#218) (@alexander-schranz)
- Move code linting into single github action with schranz/mono (#206) (@alexander-schranz)
- Update dependencies and spiral phpstan baseline (#217) (@alexander-schranz)
- Update Symfony Example to 6.3 (#207) (@alexander-schranz)
- Fix dependantbot directories (#216) (@alexander-schranz)
- Enable dependabot (#213) (@alexander-schranz)
- Add memory adapter to README (#209) (@alexander-schranz)
- Remove general pull_request action (#210) (@alexander-schranz)
- Replace github action target from pull_request to pull_request_target (#208) (@alexander-schranz)
- Add mono for managing the repository (#205) (@alexander-schranz)
- Update dependencies and fix code style (#204) (@alexander-schranz)
- Add documentation how to create own adapter (#203) (@alexander-schranz)
- Fix small typo (#197) (@jmsche)
Release 0.1.1 (2023-06-05)
- Update Meilisearch docker image (#196) (@alexander-schranz)
- Fix Yii example skeleton (#191) (@alexander-schranz, Thx @vjik)
- Increase docker health check retries (#195) (@alexander-schranz)
- Fix race condition with async algolia index create and drop index commands (#194) (@alexander-schranz)
- Update docker compose files (#193) (@alexander-schranz)
- Add Algolia DSN handling and additional config (#192) (@alexander-schranz)
- Update dependencies (#190) (@alexander-schranz)
First Release of SEAL (2023-05-16)
Schranz Search - First Release of SEAL
Monorepository for SEAL a Search Engine Abstraction Layer with support to different search engines
Documentation | Packages
Elasticsearch | Opensearch | Meilisearch | Algolia | Solr | Redisearch | Typesense
PHP | Symfony | Laravel | Spiral | Mezzio | Yii
Hello and welcome 👋,
About six month ago at the beginning of December 2022 I started the "Schranz-Search" project, which later out of that SEAL was born. At first more the project starteed as a research around different search engines which are around. At that time with a very limited knowledge about alternatives to Elasticsearch I was very curious what exists "beyond the tellerrand". With the support of different communities around Twitter, Reddit, Meetups, .. I could create a list of different search engines, and the list was bigger then expected and still grows.
My personally experience being a Core Developer at Sulu CMS a Symfony based CMS was limited to Elasticsearch. After having a look at the different search engines which did exist, I had to sortout which ones make sense to add to such an abstraction and are mostly used by the PHP community. Beside Opensearch, which should as a fork of Elasticsearch be a easy way to support, I did have a look at Algolia and Meilisearch and had so the first punch of search engines together I wanted to support. And so the start was created for SEAL the Search Engine Abstraction Layer.
Avoiding bringing complexity and search jargons to the end user
Search engines can be complex and they all have their own terms for different things. The target for the project was to hide the complexity of different search engines behind a easy understandable interface and so be very beginner friendly. The important part here was how the definition of the data which wanted to be added to the search engine need to be structured. Different search engines have different terms to define their mappings, fields, options, ... In the search engine abstraction layer wanted to avoid this kind of terms like doc_values: true
, index: true
, TAGS
, keyword
or other special terms of the different search engines. In the research I did stumble over Meilisearch definitions and really liked how they are targetting this issue. Instead of using some special search jargons terms in Meilisearch you are just telling what you want todo with the data fields you are indexing / saving. So a simple configuration inspired by Meilisearch was shipped to SEAL by using simple understandable words like searchable
, filterable
and sortable
. So the following Schema
definitions was born:
<?php
use Schranz\Search\SEAL\Schema\Field;
use Schranz\Search\SEAL\Schema\Index;
use Schranz\Search\SEAL\Schema\Schema;
$schema = new Schema([
'blog' => new Index('blog', [
'id' => new Field\IdentifierField('id'),
'title' => new Field\TextField('title', sortable: true),
'description' => new Field\TextField('description'),
'tags' => new Field\TextField('tags', multiple: true, filterable: true),
'published' => new Field\DateTimeField('published', sortable: true),
'comments' => new Field\ObjectField('comments', [
'text' => new Field\TextField('text', searchable: false),
'author' => new Field\IntegerField('author'),
], multiple: true),
]),
]);
To be near as possible to PHP with the definitions the following types where supported Text
, Integer
, Float
, Boolean
and DateTime
. This way all kind of different PHP Types are represented, with the multiple
flag every type could also be an array of data. And with a special type called Object
even assocative arrays could be added.
Strict vs. Dynamic Schema
There was nearly no discussion for me about going with a dynamic schema, I always wanted to go with a strict Schema like it is defined for databases. The first case was not all search engines supporting dynamic schemas. If you are new the search engines this means that you can push any data to it and by some kind of magic the search engines put that field into a specific type and configuration e.g. a string will by a text type in elasticsearch and so on, but if the first inputted string looks like a date it is a date field type and additional text will fail. My experience with this kind of mechanism was really bad and I only recommend it for quick prototyping. To go with a fixed and strict schema I wanted to prevent unwanted magic and add support for a wider range of search engines which do not support that kind of magic.
Creating a single interface to communicate with the search engine
After defining the definitions of the fields. The next and most important part was how the create the interface for the user of the library to communicate with the search engines. I'm really a big fan of @frankdejonge work with Flysystem, an abstraction for local and remote filesystems. It uses a single class and the Adapter Design Pattern to communicate with the different systems. That was the pattern we definitely can reuse for our abstraction. Another library which did also have an impact of the architecture is @doctrine, in the first implementation of SEAL I did go with a SchemaManager
and a Connection
, which is very similar how the Doctrine/DBAL works. After some implementation of different Adapters I decided to split the Connection
class into two seperate classes the Indexer
and the Searcher
. Thx here to @wachterjohannes and @Toflar who helped me find a good way for splitting the read and write and so make things like a ReadWriteAdapter
a lot easier. But back to the more important class the Engine
, which is responsible for providing a single interface for the end user of the library to comunicate with there different search engines. For this we added the following methods to it:
interface EngineInterface
{
public function saveDocument(string $index, array $document): void;
public function deleteDocument(string $index, string $identifier): void;
/**
* @throws DocumentNotFoundException
*
* @return array<string, mixed>
*/
public function getDocument(string $index, string $identifier): array;
public function createSearchBuilder(): SearchBuilder;
public function createIndex(string $index): void;
public function dropIndex(string $index): ?TaskInterface;
public function existIndex(string $index): bool;
public function createSchema(): void;
public function dropSchema(): void;
}
The usage of string
representation of the index
make it easier for the end user, without any imports or loading they are able with an instance of the Engine
to add, delete, search and manage there search engines indexes. Internal the Engine
forwards the Index
instance and so the configured fields to the Adapter
so that the adapter can work with it.
Fighting the search engines
The main difficulty was to fight the different search engines mappings, schemas, field definitions to match into the defined Field with options with searchable
, filterable
and sortable
. For example to make a field only filterable
and not searchable
I first thought its enough to index it in Elasticsearch as a Keyword. But still if you did search for the whole word it did still show up the document in the result. After some deep diving into Elasticsearch and Lucene I found out that I could achieve it by configure the field index: false
but doc_values: true
. This was the only solution I found for this kind of options on my side that Elasticsearch behave the expected way. The most easiest thing as our own mapping implemented the same way was the support for Meilisearch as it uses nearly the same type of configurations. For Algolia I first thought it is the same, but sorting in Algolia requires additional replica indexes. This is also why a strict schema is required for the Search Engine abstraction that we now at creating time of the Indexes which Indexes we need to create. So at the creating time of the Indexes for Algolia we create in the AlgoliaSchemaManager additional replicas which have the specific sorting defined. At search time we are using that replica and it returns us then the result in the expected order.
Beside Elasticsearch, Opensearch, Algolia and Meilisearch I also later added the support for Solr (because used widely in the @typo3 community), RediSearch (personally a big fan of @redis) and Typesense (which did come up sometimes in my research on Reddit). With some kind of community help from the different Search Engines I could implement Solr via its Cloud mode and Typesense ...