Pesquise no sistema de informações corporativas - já a partir dessa frase, ela fica presa na boca. É bom que você tenha uma, nem precisa pensar em uma experiência positiva do usuário. Como reverter a atitude dos usuários estragados pelos mecanismos de pesquisa e criar um produto rápido, preciso e perfeitamente compreensível? Precisamos pegar uma boa parte do Elasticsearch, um punhado de serviços inteligentes e amassá-los neste guia.
Existem muitos artigos sobre como fixar a pesquisa de texto completo com base no Elasticsearch no banco de dados existente. Mas claramente não há artigos suficientes sobre como fazer uma pesquisa realmente inteligente.
Ao mesmo tempo, a frase "Pesquisa Inteligente" já se transformou em um chavão e é usada para o local e não. Então, o que um mecanismo de pesquisa deve fazer para ser considerado inteligente? Por fim, isso pode ser descrito como fornecendo o resultado que o usuário realmente precisa, mesmo que esse resultado não corresponda exatamente ao texto da solicitação. Mecanismos de pesquisa populares como Google e Yandex vão além e não apenas encontram as informações necessárias, mas respondem diretamente às perguntas dos usuários.
Ok, não tomaremos uma decisão de ultimato imediatamente, mas o que pode ser feito para aproximar uma pesquisa de texto completo regular de uma pesquisa inteligente ?
Elementos de inteligência
Pesquisa inteligente - este é apenas o caso em que a quantidade pode ter qualidade e muitos recursos pequenos e bastante simples podem formar uma sensação de mágica.
- Correção de erros do usuário - se é um erro de digitação, um layout incorreto ou talvez uma solicitação com um número suspeito de resultados, mas semelhante a uma solicitação para a qual há muito mais informações.
- Para
th Bate-papos de PNL (processamento de linguagem natural, não o que você pensou) - se o usuário inseriu ofertas comerciais no último ano , ele realmente queria procurar essas palavras no texto de todos os documentos ou realmente precisava apenas de ofertas comerciais e somente no ano passado ? - Preveja entrada com base em consultas anteriores ou documentos populares.
- A apresentação do resultado é o destaque usual do fragmento encontrado, informações adicionais dependendo do que você estava procurando. Como as propostas comerciais eram necessárias no parágrafo anterior, talvez faça sentido mostrar imediatamente o assunto da proposta e de qual organização ela veio?
- Pesquisa detalhada - a capacidade de refinar a consulta de pesquisa usando filtros e facetas adicionais.
Introdutório
Há um ECM DIRECTUM com muitos documentos. O documento consiste em um cartão com meta-informação e um corpo, que pode ter várias versões.
O objetivo é procurar rápida e convenientemente informações nesses documentos da maneira usual para um usuário de mecanismos de pesquisa.
Indexação
Para procurar algo bem, você precisa indexá-lo bem primeiro.
Os documentos no ECM não são estáticos, os usuários modificam o texto, criam novas versões, alteram os dados nos cartões; novos documentos são constantemente criados e os antigos são excluídos.
Para manter as informações atualizadas no Elasticsearch, os documentos precisam ser constantemente reindexados. Felizmente, o ECM já possui sua própria fila de eventos assíncronos; portanto, quando você altera um documento, basta adicioná-lo à fila para indexação.
Mapeando documentos ECM para documentos Elasticsearch
Um corpo do documento no ECM pode ter várias versões. No Elasticsearch, isso pode ser pensado como uma matriz de objetos aninhados, mas torna-se inconveniente trabalhar com eles - fica mais difícil escrever consultas, ao alterar uma das versões, você precisa reindexar tudo, versões diferentes do mesmo documento não podem ser armazenadas em índices diferentes (por que isso pode ser necessário - na próxima seção). Portanto, desnormalizamos um documento do ECM em vários documentos do Elasticsearch com o mesmo cartão, mas com corpos diferentes.
Além do cartão e do corpo, várias informações de serviço são adicionadas ao documento Elasticsearch, que vale a pena mencionar separadamente:
- uma lista de IDs de grupos e usuários que têm direitos sobre o documento - para pesquisas com direitos;
- o número de chamadas para o documento - para ajustar a relevância;
- hora da última indexação.
Composição do Índice
Sim, índices plurais. Geralmente, vários índices para armazenar informações com significado semelhante no Elasticsearch são usados apenas se essas informações forem imutáveis e vinculadas a algum tipo de período de tempo, por exemplo, logs. Em seguida, os índices são criados todos os meses / dia ou mais frequentemente, dependendo da intensidade da carga. No nosso caso, qualquer documento pode ser alterado, e seria possível armazenar tudo em um índice.
Mas - os documentos no sistema podem estar em diferentes idiomas, e o armazenamento de dados multilíngues no Elasticsearch traz 2 problemas:
- Stemming errado. Para algumas palavras, a base será encontrada corretamente, para algumas - incorretamente (haverá outra palavra no índice), para algumas - não será encontrada (o índice ficará entupido com as formas de palavras). Para algumas palavras de idiomas diferentes e com significados diferentes, a base será a mesma e, em seguida, o significado da palavra será perdido. O uso de várias hastes consecutivas pode levar a um cálculo adicional da base para uma já calculada.
Stamming - encontrar a base da palavra. O caule não precisa ser a raiz da palavra ou sua forma normal. Geralmente, basta que as palavras relacionadas sejam projetadas em uma estrutura.
A lematização é um tipo de derivação em que a forma normal (vocabulário) de uma palavra é considerada a base.
- Frequência incorreta de palavras. Alguns mecanismos de determinação de relevância no ES levam em consideração a frequência das palavras pesquisadas no documento (quanto mais frequentemente, maior a relevância) e a frequência das palavras pesquisadas no índice (quanto mais frequentemente, menor a relevância). Portanto, uma pequena disseminação da fala russa em um documento em inglês, quando os documentos em inglês estiverem predominantemente no índice, terá alto peso, mas vale a pena misturar os documentos em inglês e russo no índice, e o peso diminuirá.
O primeiro problema pode ser resolvido para o caso em que idiomas diferentes usam conjuntos de caracteres diferentes (documentos em russo-inglês usam letras cirílicas e latinas) - os tradutores de idiomas processam apenas "seus" caracteres.
Apenas para resolver o segundo problema, usamos a abordagem com um índice separado para cada idioma.
Combinando as duas abordagens, obtemos índices de idiomas, que contêm analisadores para vários idiomas que não se cruzam em conjuntos de caracteres: russo-inglês (e separadamente inglês-russo), polonês-russo, alemão-russo, ucraniano-inglês etc. .
Para não criar antecipadamente todos os índices possíveis, usamos modelos de índice - o Elasticsearch permite especificar um modelo que contém configurações e mapeamentos e especificar um padrão de nome de índice. Quando você tenta indexar um documento em um índice inexistente, cujo nome corresponde a um dos padrões do modelo, não apenas um novo índice será criado, mas as configurações e os mapeamentos do modelo correspondente serão aplicados a ele.
Estrutura do índice
Para indexação, usamos dois analisadores de uma só vez (por vários campos): padrão para pesquisar por frase exata e personalizado para todo o resto:
"ru_en_analyzer": { "filter": [ "lowercase", "russian_morphology", "english_morphology", "word_delimiter", "ru_en_stopwords" ], "char_filter": [ "yo_filter" ], "type": "custom", "tokenizer": "standard"}
Com o filtro em minúsculas, tudo fica claro, vou falar sobre o resto.
Os filtros russian_morphology e english_morphology destinam-se à análise morfológica do texto em russo e em inglês, respectivamente. Eles não fazem parte do Elasticsearch e são incluídos como parte de um plug-in de análise-morfologia separado. Estes são lematizadores que usam a abordagem de vocabulário em combinação com algumas heurísticas e funcionam significativamente MUITO, melhor do que os filtros internos para os idiomas correspondentes.
POST _analyze { "analyzer": "russian", "text": " " } >>
E:
POST _analyze { "analyzer": "ru_en_analyzer", "text": " " } >>
Filtro word_delimiter muito curioso. Por exemplo, ajuda a eliminar erros de digitação quando não há espaço após o ponto. Usamos a seguinte configuração:
"word_delimiter": { "catenate_all": "true", "type": "word_delimiter", "preserve_original": "true" }
O yo_filter permite ignorar a diferença entre E e E:
"yo_filter": { "type": "mapping", "mappings": [ " => ", " => " ] }
tipo de filtro ru_en_stopwords stop - nosso dicionário de palavras stop.
Processo de indexação
Os corpos dos documentos no ECM são, em regra, arquivos de formatos de escritório: .docx, .pdf, etc. Para extrair o texto, o plug-in de inserção de anexo é usado com o seguinte pipeline:
{ "document_version": { "processors": [ { "attachment": { "field": "content", "target_field": "attachment", "properties": [ "content", "content_length", "content_type", "language" ], "indexed_chars": -1, "ignore_failure": true } }, { "remove": { "field": "content", "ignore_failure": true } }, { "script": { "lang": "painless", "params": { "languages": ["ru", "en" ], "language_delimeter": "_" }, "source": "..." } }, { "remove": { "field": "attachment", "ignore_failure": true } } ] } }
Do incomum no pipeline, ignorar erros da ausência do corpo (isso acontece para documentos criptografados) e determinar o índice de destino com base no idioma do texto. O último é feito em um roteiro indolor, cujo corpo darei separadamente, porque devido a restrições JSON, ele deve ser gravado em uma linha. Juntamente com dificuldades de depuração (a maneira recomendada é lançar exceções aqui e ali), ela se torna completamente dolorosa.
if (ctx.attachment != null) { if (params.languages.contains(ctx.attachment.language)) ctx._index = ctx._index + params.language_delimeter + ctx.attachment.language; if (ctx.attachment.content != null) ctx.content = ctx.attachment.content; if (ctx.attachment.content_length != null) ctx.content_length = ctx.attachment.content_length; if (ctx.attachment.content_type != null) ctx.content_type = ctx.attachment.content_type; if (ctx.attachment.language != null) ctx.language = ctx.attachment.language; }
Assim, sempre enviamos o documento para index_name . Se o idioma não estiver definido ou não for suportado, o documento será estabelecido nesse índice, caso contrário, ele se enquadra no index_name_language .
Não armazenamos o corpo original do arquivo, mas o campo _source está ativado, porque é necessário atualizar parcialmente o documento e destacar o encontrado.
Se apenas o cartão foi alterado desde a última indexação, usamos a API Atualizar por consulta sem pipeline para atualizá-lo. Isso permite, em primeiro lugar, não extrair corpos de documentos potencialmente pesados do ECM e, em segundo lugar, acelera significativamente a atualização no lado do Elasticsearch - você não precisa extrair o texto dos documentos dos formatos de escritório, o que consome muitos recursos.
Como tal, não há nenhuma atualização do documento no Elasticsearch, tecnicamente, ao atualizar a partir do índice, o documento antigo é retirado, alterado e completamente indexado novamente.
Mas se o corpo foi alterado, o documento antigo geralmente é excluído e indexado do zero. Isso permite que os documentos sejam movidos de um índice de idioma para outro.
Pesquisar
Para facilitar a descrição, darei uma captura de tela do resultado final

Texto completo
O principal tipo de consulta que temos é a Query Simple Query String Query :
"simple_query_string": { "fields": [ "card.d*.*_text", "card.d*.*_text.exact", "card.name^2", "card.name.exact^2", "content", "content.exact" ], "query": " ", "default_operator": "or", "analyze_wildcard": true, "minimum_should_match": "-35%", "quote_field_suffix": ".exact" }
onde .exact são os campos indexados pelo analisador padrão . A importância do nome do documento é duas vezes maior que o restante dos campos. A combinação de "default_operator": "or"
e "minimum_should_match": "-35%"
permite encontrar documentos que não contêm até 35% das palavras pesquisadas.
Sinônimos
Em geral, diferentes analisadores são usados para indexação e pesquisa, mas a única diferença neles é a adição de um filtro para adicionar sinônimos à consulta de pesquisa:
"search_analyzer": { "filter": [ "lowercase", "russian_morphology", "english_morphology", "synonym_filter", "word_delimiter", "ru_en_stopwords" ], "char_filter": [ "yo_filter" ], "tokenizer": "standard" }
"synonym_filter": { "type": "synonym_graph", "synonyms_path": "synonyms.txt" }
Direitos contábeis
Para pesquisas baseadas em direitos, a consulta principal é incorporada na Consulta Bool , com a adição de um filtro:
"bool": { "must": [ { "simple_query_string": {...} } ], "filter": [ { "terms": { "rights": [ ] } } ] }
Como lembramos da seção sobre indexação, o índice possui um campo com o ID de usuários e grupos que têm direitos sobre o documento. Se houver uma interseção desse campo com a matriz passada, haverá direitos.
Ajuste de Relevância
Por padrão, o Elasticsearch avalia a relevância dos resultados usando o algoritmo BM25 usando a consulta e o texto do documento. Decidimos que mais três fatores devem influenciar a avaliação da conformidade com o resultado desejado e real:
- a hora da última edição do documento - quanto mais ele estava no passado, menos provável era a necessidade desse documento;
- o número de chamadas para o documento - quanto mais, maior a probabilidade de que este documento seja necessário;
As versões do corpo do ECM têm vários estados possíveis: sendo desenvolvidos, operacionais e obsoletos. É lógico que a atuação seja mais importante que as outras.
Você pode obter esse efeito com a ajuda da função Score Query :
"function_score": { "functions": [ { "gauss": { "modified_date": { "origin": "now", "scale": "1095d", "offset": "31d", "decay": 0.5 } } }, { "field_value_factor": { "field": "access_count", "missing": 1, "modifier": "log2p" } }, { "filter": { "term": { "life_stage_value_id": { "value": "" } } }, "weight": 1.1 } ], "query": { "bool": {...} } }
Como resultado, ceteris paribus, obtemos aproximadamente a seguinte dependência do modificador de classificação de resultados na data de sua última alteração X e no número de ocorrências Y:

Inteligência externa
Para parte da funcionalidade da pesquisa inteligente, precisamos extrair vários fatos da consulta de pesquisa: datas com sua aplicação (criação, modificação, aprovação etc.), nomes de organizações, tipos de documentos procurados etc.
Também é desejável classificar a solicitação em uma determinada categoria, por exemplo, documentos por organização, funcionário, órgão regulador etc.
Essas duas operações são executadas pelo Módulo Inteligente ECM - DIRECTUM Ario .
Processo de pesquisa inteligente
É hora de considerar mais detalhadamente quais mecanismos são implementados elementos de inteligência.
Correção de erro do usuário
A correção do layout é determinada com base no modelo de idioma do trigrama - para uma linha, é calculado qual a probabilidade de atender às seqüências de três caracteres em textos em inglês e russo. Se o layout atual for considerado menos provável, primeiro, uma dica com o layout correto será exibida:

e segundo, as etapas adicionais da pesquisa são executadas com o layout correto:

E se nada puder ser encontrado com o layout corrigido, a pesquisa começará com a linha original.
A correção de erros de digitação é implementada usando o Phrase Suggester . Existe um problema: se você executar uma consulta em vários índices ao mesmo tempo, sugira que não retorne nada, enquanto que, se você executar em apenas um índice, haverá resultados. Isso é tratado definindo confiança = 0, mas, em seguida, sugira sugerir a substituição de palavras por sua forma normal. Concordo, será estranho quando você procurar por "letra a " para obter uma resposta no espírito: Talvez você estivesse procurando uma carta?
Isso pode ser contornado usando dois prompts na solicitação:
"suggest": { "content_suggest": { "text": " ", "phrase": { "collate": { "query": { {{suggestion}} } }, } }, "check_suggest": { "text": "", "phrase": { "collate": { "query": { {{suggestion}} - ({{source_query}}) }, "params": { "source_query": " " } }, } } }
Dos parâmetros comuns usados
"confidence": 0.0, "max_errors": 3.0, "size": 1
Se o primeiro opinador retornou o resultado, mas o segundo não, esse resultado é a própria string original, possivelmente com palavras de outras formas, e não há necessidade de mostrar uma dica. Se a dica ainda for necessária, a frase de pesquisa original será mesclada à dica. Isso acontece substituindo apenas as palavras corrigidas e somente aquelas que o corretor ortográfico (usando Hunspell) considera incorretas.
Se a pesquisa na cadeia de origem retornou 0 resultados, ela será substituída pela cadeia obtida pela mesclagem e a pesquisa será realizada novamente:

Caso contrário, a sequência de prompt resultante será retornada apenas como um prompt para a pesquisa:

Classificação de consulta e extração de fatos
Como mencionei, usamos o DIRECTUM Ario, a saber, o serviço de classificação de texto e o serviço de extração de fatos. Para fazer isso, fornecemos aos analistas consultas de pesquisa anônimas e uma lista de fatos nos quais estamos interessados. Com base em consultas e conhecimento sobre quais documentos estão no sistema, os analistas identificaram várias categorias e treinaram o serviço de classificação para determinar a categoria de acordo com o texto da consulta. Com base nas categorias resultantes e na lista de fatos, formulamos as regras para o uso desses fatos. Por exemplo, a frase do último ano na categoria Todos é considerada a data de criação do documento e na categoria Por organização - a data do registro. Ao mesmo tempo, os criados no ano passado devem, em qualquer categoria, cair na data de criação.
Do lado da pesquisa - eles fizeram uma configuração na qual registraram as categorias, quais fatos são aplicados a quais filtros de faceta.
Conclusão da entrada
Além das correções de layout já mencionadas, pesquisas anteriores do usuário e documentos públicos caem no preenchimento automático.

Eles são implementados usando outro tipo de Sugeridor - Sugeridor de conclusão , mas cada um tem suas próprias nuances.
Preenchimento automático: histórico de pesquisa
Existem muito menos usuários no ECM que os mecanismos de pesquisa e alocam consultas comuns suficientes para eles por que lenin cogumelo não é possível. Mostrar tudo em uma linha também não vale a pena devido a considerações de privacidade. O Sugestor de Conclusão usual pode pesquisar apenas o conjunto inteiro de documentos no índice, mas o Context Suggester vem em socorro - uma maneira de definir um contexto para cada dica e filtrar por esses contextos. Se os nomes de usuário forem usados como contextos, apenas a história dele poderá ser mostrada a todos.
Você também precisa dar ao usuário a oportunidade de remover o prompt pelo qual ele tem vergonha. Como chave para exclusão, usamos o nome do usuário e o texto da dica de ferramenta. Como resultado, para o índice com dicas, obtivemos um mapeamento tão duplicado:
"mappings": { "document": { "properties": { "input": { "type": "keyword" }, "suggest": { "type": "completion", "analyzer": "simple", "preserve_separators": true, "preserve_position_increments": true, "max_input_length": 50, "contexts": [ { "name": "user", "type": "CATEGORY" } ] }, "user": { "type": "keyword" } } } }
O peso de cada nova dica é definido como um e aumenta cada vez que você a digita novamente usando a API Atualizar por consulta com um script ctx._source.suggest.weight++
muito simples.
Preenchimento automático: documentos
Mas pode haver muitos documentos e possíveis combinações de direitos. Portanto, aqui, pelo contrário, decidimos não fazer a filtragem por direitos ao preencher automaticamente, mas apenas indexar documentos públicos. Sim, e você não precisa remover dicas individuais desse índice. Parece que a implementação em tudo é mais fácil do que a anterior, se não por dois pontos:
O primeiro - o Completion Suggester oferece suporte apenas à pesquisa de prefixos, e os clientes adoram atribuir números de itens a tudo, e algumas .01.01
ao digitar uma consulta. Aqui, junto com o nome completo, você também pode indexar n-gramas derivados:
{ "extension": "pdf", "name": ".01.01 ", "suggest": [ { "input": "", "weight": 70 }, { "input": " ", "weight": 80 }, { "input": " ", "weight": 90 }, { "input": ".01.01 ", "weight": 100 } ] }
Isso não foi tão crítico com a história, mas o mesmo usuário entra aproximadamente na mesma linha se ele procurar algo novamente. Provavelmente .
A segunda - por padrão, todas as dicas são iguais, mas gostaríamos de torná-las mais iguais e de preferência para que isso seja consistente com a classificação dos resultados da pesquisa. Para fazer isso, repita aproximadamente as funções gauss e field_value_factor usadas na Consulta de Pontuação da Função .
Acontece que aqui está um pipeline:
{ "dir_public_documents_pipeline": { "processors": [ ... { "set": { "field": "terms_array", "value": "{{name}}" } }, { "split": { "field": "terms_array", "separator": "\\s+|$" } }, { "script": { "source": "..." } } ] } }
com o seguinte script:
Date modified = new Date(0); if (ctx.modified_date != null) modified = new SimpleDateFormat('dd.MM.yyyy').parse(ctx.modified_date); long dayCount = (System.currentTimeMillis() - modified.getTime())/(1000*60*60*24); double score = Math.exp((-0.7*Math.max(0, dayCount - 31))/1095) * Math.log10(ctx.access_count + 2); int count = ctx.terms_array.length; ctx.suggest = new ArrayList(); ctx.suggest.add([ 'input': ctx.terms_array[count - 1], 'weight': Math.round(score * (255 - count + 1)) ]); for (int i = count - 2; i >= 0 ; --i) { if (ctx.terms_array[i].trim() != "") { ctx.suggest.add([ "input": ctx.terms_array[i] + " " + ctx.suggest[ctx.suggest.length - 1].input, "weight": Math.round(score * (255 - i))]); } } ctx.remove('terms_array'); ctx.remove('access_count'); ctx.remove('modified_date');
Por que se preocupar com um oleoduto indolor em vez de escrevê-lo em um idioma mais conveniente? Como agora, usando a API Reindex , você pode substituir o conteúdo dos índices de pesquisa em índices para obter dicas (especificando apenas os campos necessários, é claro) em apenas um comando.
A composição dos documentos públicos realmente necessários não é atualizada com frequência, portanto esse comando pode ser deixado em um início manual.
Exibir resultados
Categorias
A categoria determina quais facetas estarão disponíveis e como será o snippet. Ele pode ser detectado automaticamente por inteligência externa ou selecionado manualmente acima da barra de pesquisa.
Facetas
As facetas são uma coisa tão intuitiva para todos cujo comportamento, no entanto, é descrito por regras muito triviais. Aqui estão alguns deles:
Os valores das facetas dependem dos resultados da pesquisa, MAS os resultados da pesquisa dependem das facetas selecionadas. Como evitar recursão?
A seleção de valores em uma faceta não afeta outros valores dessa faceta, mas afeta valores em outras facetas:

- Os valores de faceta selecionados pelo usuário não devem desaparecer, mesmo se uma opção em outra faceta os aniquilar para 0 ou eles não estiverem mais no topo:

Na elasticidade, as facetas são realizadas através do mecanismo de agregação, mas, para cumprir as regras descritas, essas agregações devem ser investidas uma na outra e filtradas uma pela outra.
Considere os fragmentos de solicitação responsáveis por isso:
Código muito grande { ... "post_filter": { "bool": { "must": [ { "terms": { "card.author_value_id": [ "1951063" ] } }, { "terms": { "editor_value_id": [ "2337706", "300643" ] } } ] } }, "query": {...} "aggs": { "card.author_value_id": { "filter": { "terms": { "editor_value_id": [ "2337706", "300643" ] } }, "aggs": { "card.author_value_id": { "terms": { "field": "card.author_value_id", "size": 11, "exclude": [ "1951063" ], "missing": "" } }, "card.author_value_id_selected": { "terms": { "field": "card.author_value_id", "size": 1, "include": [ "1951063" ], "missing": "" } } } }, ... "editor_value_id": { "filter": { "terms": { "card.author_value_id": [ "1951063" ] } }, "aggs": { "editor_value_id": { "terms": { "field": "editor_value_id", "size": 11, "exclude": [ "2337706", "300643" ], "missing": "" } }, "editor_value_id_selected": { "terms": { "field": "editor_value_id", "size": 2, "include": [ "2337706", "300643" ], "missing": "" } } } }, ... } }
O que há aqui que:
- post_filter permite impor uma condição adicional aos resultados de uma consulta já concluída e não afeta os resultados das agregações. Essa mesma lacuna de recursão. Inclui todos os valores selecionados de todas as facetas.
- agregações de nível superior, no exemplo card.author_value_id e editor_value_id . Cada um tem:
- filtre pelos valores de todas as outras facetas, exceto a sua;
- agregação aninhada para valores de faceta selecionados - proteção contra aniquilação ;
- agregação aninhada para outros valores de faceta. Mostramos os 10 principais e solicitamos os 11 principais - para determinar se o botão Mostrar tudo será exibido.
Snippets
Dependendo da categoria selecionada, o snippet pode parecer diferente, por exemplo, o mesmo documento ao pesquisar em uma categoria
Todos :

e funcionários :

Ou lembre-se, queríamos ver o assunto de uma oferta comercial e de quem ela veio?

Para não arrastar o cartão inteiro do elástico (isso diminui a velocidade da pesquisa), a filtragem de origem é usada :
{ ... "_source": { "includes": [ "id", "card.name", "card.card_type_value_id", "card.life_stage_value_id", "extension", ... ] }, "query": {...} ... }
Para destacar as palavras encontradas no texto do documento, o Marcador Fast Vector é usado - como gerador dos trechos mais apropriados para textos grandes e para o nome - Marcador unificado - como o menos exigente em recursos e estrutura de índice:
"highlight": { "pre_tags": [ "<strong>" ], "post_tags": [ "</strong>" ], "encoder": "html", "fields": { "card.name": { "number_of_fragments": 0 }, "content": { "fragment_size": 300, "number_of_fragments": 3, "type": "fvh" } } },
Nesse caso, o nome é destacado por inteiro e, a partir do texto, temos até 3 fragmentos com 300 caracteres. O texto retornado pelo marca-texto Fast Vector é ainda compactado por um algoritmo improvisado para obter um estado de snippet minimizado.
Reduzir
Historicamente, os usuários desse ECM estão acostumados ao fato de que a pesquisa retorna documentos para eles, mas, na verdade, o Elasticsearch pesquisa entre versões de documentos . Pode acontecer que várias versões quase idênticas sejam encontradas na mesma consulta. Isso irá confundir os resultados e confundir o usuário. Felizmente, esse comportamento pode ser evitado usando o mecanismo Field Collapsing - uma versão leve de agregações que já funciona nos resultados finais (nesse caso, ele se parece com post_filter, duas muletas são um par ). O recolhimento resultará no mais relevante dos objetos recolhidos .
{ ... "query": {...} ... "collapse": { "field": "id" } }
Infelizmente, o colapso tem vários efeitos desagradáveis, por exemplo, várias características numéricas do resultado da pesquisa continuam retornando como se não houvesse colapso. Ou seja, o número de resultados, o número de valores das facetas - todos estarão levemente incorretos, mas o usuário geralmente não percebe isso, assim como o leitor cansado, que provavelmente não leu essa proposta antes.
O fim