Representar os diferentes tipos dentro de um índice, como um usuário, um produto etc.
Representa hastes de palavras, exclusivas para todo o índice. (Por exemplo, a execução é uma haste das palavras que executam, corredor, corridas etc.). Uma frequência inversa de documentos é calculada e armazenada na palavra para fornecer um IDF em todo o índice que pode ser usado para executar pesquisas sem esquema em relação ao índice.
Um termo representa a existência de uma palavra dentro de um esquema específico. Ou seja, se a palavra time "executar" aparecer no esquema do usuário e também aparecer no esquema do produto, haverá dois registros de termos para essa palavra, dentro desse esquema. Uma frequência inversa de documentos também é armazenada ao lado do termo para fornecer um IDF específico do esquema que permite pesquisas contra um esquema específico (essas pesquisas não serão afetadas pelos valores de IDF em todo o índice para as palavras).
Uma coluna é um campo disponível em um esquema. A coluna armazena regras sobre se os dados que ela representam são armazenados, seja indexada e seu peso que pode ser usado para priorizar as colunas em consultas (por exemplo, um título do produto pode ter mais peso do que uma descrição)
Um documento representa uma entidade real em um índice, este é o item que é realmente indexado e formará a base dos resultados para consultas.
Um campo é um atributo de um documento que corresponde a uma coluna. Colunas, documentos e campos agem como um banco de dados típico. Uma coluna é como uma coluna de tabela, um documento é como uma linha ou registro e um campo é uma célula ou entrada.
Uma ocorrência representa a existência de um termo (uma palavra específica de esquema) dentro de um campo em um documento. Uma ocorrência é uma representação única de um termo e campo. Ao lado de uma ocorrência, também armazenamos uma frequência, que representa o número de vezes que o termo aparece dentro do campo (que é usado para calcular as pontuações posteriormente ao pesquisar).
As posições representam que as posições reais dos termos nos campos. Se a palavra "executar" (ou suas hastes) aparecer 3 vezes em um campo, haveria 3 registros de posição, cada um marcando a posição dessa ocorrência dentro do campo correspondente.
Imagine que temos um esquema de "usuário" em nosso índice. Esse esquema define 2 colunas para cada instância do usuário, "Nome" e "About". Cada coluna é armazenada e indexada e ambos têm um peso de 1. Temos 2 usuários para adicionar ao índice, [Chave: 1, nome: "Joe Bloggs", "Sobre": "Joe gosta de Jane"] e [Chave: 2, nome: "Jane Doe", sobre: "Jane Love To Party"]. Acabaríamos com a seguinte estrutura:
| eu ia | nome |
|---|---|
| 1 | usuário |
| eu ia | nome | armazenado | indexado | peso |
|---|---|---|---|---|
| 1 | nome | 1 | 1 | 1 |
| 2 | sobre | 1 | 1 | 1 |
| eu ia | palavra |
|---|---|
| 1 | Joe |
| 2 | blogg |
| 3 | como |
| 4 | Jane |
| 5 | corça |
| 6 | amor |
| 7 | para |
| 8 | festa |
| eu ia | schema_id | word_id | document_count |
|---|---|---|---|
| 1 | 1 | 1 | 2 |
| 2 | 1 | 2 | 1 |
| 3 | 1 | 3 | 2 |
| 4 | 1 | 4 | 3 |
| 5 | 1 | 5 | 1 |
| 6 | 1 | 6 | 1 |
| 7 | 1 | 7 | 1 |
| 8 | 1 | 8 | 1 |
| eu ia | schema_id | chave |
|---|---|---|
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| eu ia | document_id | column_id | valor |
|---|---|---|---|
| 1 | 1 | 1 | Joe Bloggs |
| 2 | 1 | 2 | Joe gosta de Jane |
| 3 | 2 | 1 | Jane Doe |
| 4 | 2 | 2 | Jane gosta de festejar |
| eu ia | campo_id | termo_id | freqüência |
|---|---|---|---|
| 1 | 1 | 1 | 1 |
| 2 | 1 | 2 | 1 |
| 3 | 2 | 1 | 1 |
| 4 | 2 | 3 | 1 |
| 5 | 2 | 4 | 1 |
| 6 | 3 | 4 | 1 |
| 7 | 3 | 5 | 1 |
| 8 | 4 | 4 | 1 |
| 9 | 4 | 3 | 1 |
| 10 | 4 | 7 | 1 |
| 11 | 4 | 8 | 1 |
| eu ia | occurrence_id | posição |
|---|---|---|
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 3 | 1 |
| 4 | 4 | 2 |
| 5 | 5 | 3 |
| 6 | 6 | 1 |
| 7 | 7 | 2 |
| 8 | 8 | 1 |
| 9 | 9 | 2 |
| 10 | 10 | 3 |
| 11 | 11 | 4 |
Quando o objeto Blixt é criado, ele carrega inicialmente todos os objetos de esquema e coluna armazenados na memória, se houver. Isso permite que o Blixt procure rapidamente um esquema e suas colunas associadas para validar uma solicitação de índice e reunir rapidamente as restrições is_indexed e is_stored em cada coluna.
Antes da indexação de um documento pode ocorrer, um esquema deve ser definido com um conjunto de colunas, cada uma com suas próprias propriedades que especificam se os campos que eles representam devem ser armazenados e ou indexados. Se já existe um esquema, essa parte poderá ser ignorada. Se uma definição de esquema não for fornecida e não existe esse esquema, uma exceção será lançada.
Um documento é fornecido na forma de um documento indexável, especificando uma chave que pode ser usada pelo sistema do cliente para identificá -lo posteriormente. Um documento indexável contém um conjunto de campos. Um esquema (ou tipo) é fornecido junto com o documento para que o Blixt possa colocar o documento no esquema correto dentro do índice.
O Blixt começa a processar o documento pela primeira vez para garantir que ele ainda não exista no índice nesse esquema. Se existir, uma exceção será lançada.
O BLIXT adicionará um registro de documento e começará a processar os campos do documento. Cada campo é dividido em tokens (na maioria dos casos, um token é uma palavra) e, em seguida, cada token é decorrente (ou seja, encontrando a raiz de uma palavra, por exemplo, com um inglês/porter, a palavra "run" é o caule das palavras "em execução", "corredor", "corre" etc.)
Os registros do Word são então adicionados para cada um dos tokens se já não houver registros correspondentes e, em seguida, os registros de termos forem criados sob o esquema de acordo. Os totais da contagem de documentos para o termo registros são atualizados para refletir a adição do novo documento.
Os registros de ocorrência são criados para cada combinação exclusiva de termo e campo, indicando que o termo especificado ocorre dentro do campo específico. A frequência (número de vezes esse termo ocorreu no campo) é armazenado ao longo do registro de ocorrência. Os dados posicionais também são armazenados em cada registro de ocorrência, representando cada posição em um campo em que ocorreu um termo.
Os seguintes tipos de consultas são suportados:
+ , que torna um termo necessário (e) ou a ~ que faz um termo remover um documento da consideração (não). Esse tipo de consulta forma a base de todas as outras consultas. A pesquisa começa dividindo a frase de pesquisa em palavras separadas (tokenização) e depois transformando cada palavra em sua forma raiz (Stemming). O índice é então consultado para encontrar registros de palavras correspondentes aos termos. Usando os registros da palavra e o esquema, estamos interrogando, os registros de termos são extraídos. Se algum dos termos de pesquisa que tivesse o operador + anexado a ele não estiver presente nos registros de termo, um conjunto de resultados vazio será retornado.
Uma consulta é realizada para encontrar campos que contêm os termos da consulta (independentemente do operador) e os documentos associados a esses campos são retornados (com seus campos, ocorrências e posições carregadas de acordo). Cada documento é analisado e aceito ou rejeitado, se um documento não contiver um termo necessário ( + ) ou contiver um termo removido ( ~ ) é rejeitado, todos os outros documentos são aceitos. O conjunto de documentos aceitos é então retornado como resultados.
Os seguintes tipos de consultas devem ser suportados posteriormente:
Consulta de termo único: semelhante a uma consulta de vários termos, os documentos são pontuados em relação a um único termo.
Consulta de frase completa: semelhante a uma consulta de vários termos, mas apenas documentos que contêm todos os termos na ordem correta são permitidos.
Também se destina a implementar a análise de consulta para que uma sequência de pesquisa de entrada possa ser convertida no tipo de consulta correta antes da pesquisa ser executada.
Essas são melhorias destinadas ao futuro.
Implementar um cache agnóstico de armazenamento (Redis, Memcached, FileSystem etc.) que podemos usar para melhorar o desempenho da pesquisa. Existem vários casos de uso para um cache neste projeto:
Nota: Para implementar alguns dos recursos acima, precisamos usar um identificador de sessão exclusivo para passar de volta e receber do usuário para garantir que as pesquisas em cache sejam válidas apenas para esse usuário e para impedir que esses objetos em cache sejam limpos. Definitivamente, esse é o caso ao armazenar em cache um conjunto completo de resultados de pesquisa para permitir que o usuário pagine. Também pode valer a pena armazenar em cache de versões que não são consideradas específicas da sessão para permitir que muitos usuários pesquisem a mesma coisa para ver os mesmos resultados de pesquisa rapidamente.
Durante o processo de indexação, podemos usar uma tabela extra para armazenar um mapeamento de termos para documentos, o que nos informará em quais documentos um determinado termo aparece. Isso nos permitiria pular muito do processo de tentar determinar os IDs de documentos do candidato, simplesmente pegando a lista de documentos em que um termo aparece para que os candidatos a gerar rapidamente (ou em case de termos proibidos, que