Um projeto divertido de escrever um mecanismo de pesquisa pequeno e ingênuo, adequado para Small Data™.
Execute testes de unidade:
mix test --exclude external
Execute todos os testes, inclusive aqueles que dependem de serviços externos. Como os testes RedisIndex
:
mix test
certifique-se de ter a connection_string correta para redis em config/config.exs . Você pode usar docker-compose
para colocar uma instância do redis em funcionamento rapidamente.
Cada índice no Cedrik é representado por um processo com o Index
@behaviour
. Para indexar algo em um índice, basta chamar Index.index_doc(something, :index_name, type)
onde something
seria um mapa ou estrutura Elixir (eu recomendaria criar uma estrutura, com um campo id que implemente o protocolo Storable
- dê uma olhada em lib/document.ex
e lib/agent_store.ex
para referência), type
deve ser uma das implementações de índice existentes AgentIndex
ou RedisIndex
. O último argumento para Index.index_doc
é opcional e o padrão é AgentIndex
.
Para obter uma lista de índices existentes, use Index.list/0
ou Index.list/1
- eles retornarão uma lista de tuplas no formato {pid, name, module}
Este é o tipo de índice in-memory ingênuo, adequado para coisas que cabem na memória e que não precisam ser persistidas.
Este é um índice apoiado por redis. Você deve ter uma instância do Redis instalada e funcionando para que isso funcione. O principal benefício de usar um RedisIndex em comparação com AgentIndex é quando você deseja persistir os dados.
Por enquanto, um token é simplesmente qualquer string separada por espaços.
Use Search.search(query_struct, [:index1, :index2])
, consulte test/e2e_test.exs
e test/query_test.exs
para obter exemplos.
Para obter um query_struct
que Cedrik entenda, existe um analisador simples (e incompleto) para strings: Query.Parse.parse/1
. Ele irá tokenizar strings e, em seguida, construir estruturas de consulta Term e Wildcard de acordo. Termos e curingas serão agrupados em um booleano, dentro do campo obrigatório.
Esta consulta retornará todos os IDs de documentos nos índices especificados.
Um TermQuery simplesmente retorna os IDs do documento (e as localizações do termo dentro desse documento) que contém o termo fornecido. Você pode especificar exatamente quais campos procurar ou todos eles (que é o padrão).
Com o BooleanQuery você pode construir consultas mais avançadas. must
, optional
e must_not
Essa consulta pode ajudar a ampliar seus acessos. Uma consulta curinga com valor "foo*"
corresponde a foo e foobar, por exemplo. Observe que apenas caracteres curinga únicos são suportados por enquanto, à esquerda ( *foo
) ou à direita ( foo*
)
No momento, os resultados de Search.search/2
fornecerão uma lista de tuplas semelhantes a: {doc_id, #MapSet<[%Location{field: :field, position: x}]>}
classificadas pelos itens com mais acessos primeiro.