Un projet amusant d'écriture d'un petit moteur de recherche naïf adapté à Small Data™.
Exécutez des tests unitaires :
mix test --exclude external
Exécutez tous les tests, y compris ceux s'appuyant sur des services externes. Tels que les tests RedisIndex
:
mix test
assurez-vous d'avoir la bonne connection_string pour redis dans config/config.exs . Vous pouvez utiliser docker-compose
pour qu'une instance Redis soit opérationnelle rapidement.
Chaque index dans Cedrik est représenté par un processus avec l' Index
@behaviour
. Pour indexer quelque chose dans un index, appelez simplement Index.index_doc(something, :index_name, type)
où something
serait une carte ou une structure Elixir (je recommanderais de créer une structure, avec un champ id qui implémente le protocole Storable
- jetez un œil à lib/document.ex
et lib/agent_store.ex
pour référence), type
doit être l'une des implémentations d'index existantes AgentIndex
ou RedisIndex
. Le dernier argument de Index.index_doc
est facultatif et est par défaut AgentIndex
.
Pour obtenir une liste d'index existants, utilisez Index.list/0
ou Index.list/1
- ceux-ci renverront une liste de tuples au format {pid, name, module}
Il s'agit du type d'index naïf en mémoire, adapté aux éléments qui tiennent en mémoire et qui n'ont pas besoin d'être conservés.
Il s'agit d'un index soutenu par Redis. Vous devez disposer d’une instance Redis opérationnelle pour que cela fonctionne. Le principal avantage de l'utilisation d'un RedisIndex par rapport à AgentIndex est lorsque vous souhaitez pouvoir conserver les données.
Pour l'instant, un jeton est simplement n'importe quelle chaîne séparée par des espaces.
Utilisez Search.search(query_struct, [:index1, :index2])
, voir test/e2e_test.exs
et test/query_test.exs
pour des exemples.
Pour obtenir une query_struct
que Cedrik comprend, il existe un analyseur simple (et incomplet) pour les chaînes : Query.Parse.parse/1
. Il tokenisera les chaînes, puis construira les structures de requête Term et Wildcard en conséquence. Les termes et les caractères génériques seront enveloppés dans un booléen, à l'intérieur du champ obligatoire.
Cette requête renverra tous les identifiants de documents dans les index spécifiés.
Un TermQuery renvoie simplement les identifiants du document (et les emplacements du terme dans ce document) qui contiennent le terme donné. Vous pouvez spécifier exactement les champs à rechercher, ou tous (ce qui est la valeur par défaut).
Avec BooleanQuery, vous pouvez créer des requêtes plus avancées. must
, optional
et must_not
Cette requête peut vous aider à élargir vos hits. Une requête Wildcard avec la valeur "foo*"
correspond à la fois à foo et foobar par exemple. Notez que seuls les caractères génériques uniques sont pris en charge pour l'instant, soit en début ( *foo
) soit en fin ( foo*
).
Pour le moment, les résultats de Search.search/2
vous donneront une liste de tuples qui ressemblent à : {doc_id, #MapSet<[%Location{field: :field, position: x}]>}
triés par les éléments les plus consultés. d'abord.