Eu queria mostrar a maioria dos novos recursos de pesquisa do Couchbase disponíveis na versão 4.5 em um projeto simples. E recentemente houve algum interesse sobre armazenamento de arquivos ou binários no Couchbase. De uma perspectiva geral e genérica, os bancos de dados não são feitos para armazenar arquivos ou binários. Normalmente, o que você faria é armazenar arquivos em um repositório binário e seus metadados associados no banco de dados. Os metadados associados serão o local do arquivo no armazenamento binário e o máximo possível de informações extraídas do arquivo.

Portanto, este é o projeto que mostrarei a você hoje. É um aplicativo Spring Boot muito simples que permite que o usuário faça upload de arquivos, armazene-os em um repositório binário, onde o texto e os metadados associados serão extraídos do arquivo, e permite que você pesquise arquivos com base nesses metadados e no texto. No final, você poderá pesquisar arquivos por tipo de imagem, tamanho da imagem, conteúdo do texto, basicamente qualquer metadado que possa ser extraído do arquivo.

A Loja Binária

Essa é uma pergunta que recebemos com frequência. Certamente é possível armazenar dados binários em um banco de dados, mas os arquivos devem estar em um armazenamento binário apropriado. Decidi criar uma implementação muito simples para este exemplo. Basicamente, há uma pasta no sistema de arquivos declarada no tempo de execução que conterá todos os arquivos carregados. Um resumo SHA1 será calculado a partir do conteúdo do arquivo e usado como nome de arquivo nessa pasta. Obviamente, você poderia usar outros armazenamentos binários mais avançados, como o Manta da Joyent ou o Amazon S3, por exemplo. Mas vamos manter as coisas simples para esta postagem :) Aqui está uma descrição dos serviços usados.

SHA1Serviço

Esse é o mais simples, com um método que basicamente envia de volta um resumo SHA-1 com base no conteúdo do arquivo. Para simplificar ainda mais o código, estou usando o Apache commons-codec:

DataExtractionService

Esse serviço foi criado para extrair metadados e texto dos arquivos carregados. Há muitas maneiras diferentes de fazer isso. Eu optei por usar o ExifTool e Poppler.

O ExifTool é uma excelente ferramenta de linha de comando para ler, gravar e editar metadados de arquivos. Ele também pode gerar metadados diretamente em JSON. E, é claro, não se limita ao padrão Exif. Ele é compatível com uma grande variedade de formatos. O Poppler é uma biblioteca de utilitários para PDF que me permitirá extrair o conteúdo de texto de um PDF. Como essas ferramentas são de linha de comando, usarei plexus-utils para facilitar as chamadas da CLI.

Há dois métodos. O primeiro é extractMetadata e é responsável pela extração de metadados do ExifTool. É o equivalente a executar o seguinte comando:

O -n está aqui para garantir que todos os valores numéricos sejam fornecidos como números e não como strings e -json para garantir que a saída esteja no formato JSON. Isso pode lhe dar uma saída como esta:

Há algumas informações interessantes, como o tipo mime, o tamanho, a data de criação e muito mais. Se o tipo mime do arquivo for aplicativo/pdf então podemos tentar extrair o texto dele com o poppler, que é o que o segundo método do serviço está fazendo. Ele é equivalente à seguinte chamada da CLI:

Esse comando envia o texto extraído para a saída padrão. Que podemos recuperar e colocar em um arquivo texto completo em um objeto JSON. Código completo do serviço abaixo:

Coisas bastante simples, como você pode ver depois de usar o plexus-utils.

BinaryStoreService

Esse serviço é responsável por executar a extração de dados e armazenar arquivos, excluir arquivos ou recuperar arquivos. Vamos começar com a parte de armazenamento. Tudo acontece no serviço storeFile método. A primeira coisa a fazer é recuperar o resumo do arquivo e, em seguida, gravá-lo na pasta de armazenamento binário declarada na configuração. Depois que o arquivo é gravado, o serviço de extração de dados é chamado para recuperar os metadados como um JsonObject. Em seguida, o local do armazenamento binário, o tipo de documento, o resumo e o nome do arquivo são adicionados a esse objeto JSON. Se o arquivo carregado for um PDF, o serviço de extração de dados será chamado novamente para recuperar o conteúdo do texto e armazená-lo em um objeto texto completo field. Em seguida, um JsonDocument é criado com o digest como chave e o JsonObject como conteúdo.

Ler ou excluir deve ser bastante simples de entender agora:

Lembre-se de que essa é uma implementação muito ingênua!

Indexação e pesquisa de arquivos

Depois de fazer o upload dos arquivos, você deseja recuperá-los. A primeira maneira muito básica de fazer isso seria exibir a lista completa de arquivos. Em seguida, você poderia usar o N1QL para pesquisá-los com base em suas metadatas ou o FTS para pesquisá-los com base em seu conteúdo.

O serviço de busca

getFiles simplesmente executa a seguinte consulta: SELECT binaryStoreLocation, binaryStoreDigest FROMpadrãoWHERE type= 'file'. Isso envia a lista completa de arquivos carregados com seu resumo e o local do armazenamento binário. Observe a opção de consistência definida como statement_plus. Como se trata de um aplicativo de documentos, prefiro uma consistência forte.

Em seguida, você tem searchN1QLFiles que executa uma consulta N1QL básica com uma cláusula WHERE adicional. Portanto, o padrão é a mesma consulta acima com uma parte WHERE adicional. Até o momento, não há uma integração mais estreita. Poderíamos ter um formulário de pesquisa sofisticado que permitisse ao usuário pesquisar arquivos com base em seus tipos de mime, tamanho ou quaisquer outros campos fornecidos pelo ExifTool.

E, finalmente, você tem searchFulltextFiles que recebe uma String como entrada e a usa em um Jogo consulta. Em seguida, o resultado é enviado de volta com fragmentos de texto em que o termo foi encontrado. Esse fragmento permite destacar o termo no contexto. Também solicito o binaryStoreDigest e binaryStoreLocation campos. Eles são usados para exibir os resultados para o usuário.

O TermQuery.on define qual índice estou consultando. Aqui ele está definido como 'file_fulltext'. Isso significa que criei um índice de texto completo com esse nome:

Colocando tudo junto

Configuração

Primeiro, uma breve explicação sobre a configuração. A única coisa configurável até agora é o caminho do armazenamento binário. Como estou usando o Spring Boot, só preciso do seguinte código:

Com isso, posso simplesmente adicionar binaryStore.root=/Usuários/ldoguin/binaryStore para minha application.properties arquivo. Também quero permitir o upload de um arquivo de 512 MB, no máximo. Além disso, para aproveitar a autoconfiguração do Spring Boot Couchbase, preciso adicionar o endereço do meu servidor Couchbase. No final, meu application.properties se parece com isso:

Para usar o autoconfig do Spring Boot, basta ter o spring-boot-starter-parent como pai e o Couchbase no classpath. Portanto, é apenas uma questão de adicionar uma dependência java-client do Couchbase. Estou especificando a versão 2.2.4 aqui porque o padrão é 2.2.3 e o FTS está apenas na versão 2.2.4. Você pode dar uma olhada no arquivo pom completo em Github. Parabéns a Stéphane Nicoll da Pivotal e Simon Baslé do Couchbase para essa maravilhosa integração com o Spring.

Controlador

Como esse aplicativo é muito simples, coloquei tudo no mesmo controlador. O ponto de extremidade mais básico é /arquivos. Ele exibe a lista de arquivos já carregados. Basta uma chamada para o searchService, colocar o resultado no modelo da página e, em seguida, renderizar a página.

Eu uso Folha de tomilho para renderização e IU semântica como estrutura CSS. Você pode dar uma olhada no modelo usado aqui. Esse é o único modelo usado no aplicativo.

Quando tiver uma lista de arquivos, você poderá fazer o download ou excluí-los. Ambos os métodos estão chamando o método de serviço de armazenamento binário, e o restante do código é o clássico Spring MVC:

Obviamente, você também desejará fazer upload de alguns arquivos. É um simples POST multiparte. O serviço de armazenamento binário é chamado, persiste o arquivo e extrai os dados apropriados e, em seguida, redireciona para o /arquivos ponto final.

Os dois últimos métodos são usados para a pesquisa. Eles simplesmente chamam o serviço de pesquisa, adicionam o resultado ao modelo da página e o renderizam.

E isso é praticamente tudo o que você precisa para armazenar, indexar e pesquisar arquivos com o Couchbase e o Spring Boot. É um aplicativo simples e há muitas, muitas outras coisas que você poderia fazer para melhorá-lo, começando por um formulário de pesquisa adequado que exponha os campos extraídos do ExifTool. Vários uploads de arquivos e arrastar e soltar seriam uma boa vantagem. O que mais você gostaria de ver? Deixe-nos saber nos comentários abaixo!

Autor

Postado por Laurent Doguin

Laurent é um nerd metaleiro que mora em Paris. Em sua maior parte, ele escreve código em Java e texto estruturado em AsciiDoc, e frequentemente fala sobre dados, programação reativa e outras coisas que estão na moda. Ele também foi Developer Advocate do Clever Cloud e do Nuxeo, onde dedicou seu tempo e experiência para ajudar essas comunidades a crescerem e se fortalecerem. Atualmente, ele dirige as Relações com Desenvolvedores na Couchbase.

Deixar uma resposta