Técnico

Como implementar rapidamente um sistema de busca de texto usando o pyvespa

Compartilhar

Intro

Nos sistemas modernos de recuperação de informações, os modelos de aprendizado de máquina são aproveitados. Esses modelos são muito mais pesados e apresentam vários desafios de implementação, o que significa que soluções personalizadas são quase impossíveis de escalar e distribuir. As soluções existentes, como o Elastic Search, carecem de funcionalidade, pois não foram projetadas para modelos de aprendizado profundo. É aqui que a Vespa vem para facilitar as coisas. Este blog é para aqueles curiosos sobre soluções inovadoras para os problemas que surgem da implementação de um sistema de recuperação de informações. Aqui, abordaremos uma maneira rápida e fácil de implementar um sistema de pesquisa de texto usando a API python da Vespa, pyvespa.

O que é Vespa

A Vespa é uma plataforma para aplicativos que precisam de computação de baixa latência em grandes bancos de dados. Ele armazena e indexa seus dados estruturados, de texto e vetoriais para que as consultas, a seleção e o processamento e a inferência do modelo aprendido por máquina sobre os dados possam ser executados rapidamente no horário de entrega em qualquer escala. Ele permite que você grave e mantenha qualquer quantidade de dados e execute grandes volumes de consultas sobre os dados, que normalmente são concluídas em dezenas de milissegundos. As consultas podem usar as condições de pesquisa vetorial, texto e filtro do vizinho mais próximo para selecionar dados. Todos os dados correspondentes são então classificados de acordo com as funções de classificação — normalmente aprendidas por máquina — para implementar casos de uso como relevância de pesquisa, recomendação, segmentação e personalização. Todos os dados correspondentes também podem ser agrupados em grupos e subgrupos, nos quais os dados são agregados para cada grupo para implementar recursos como gráficos, nuvens de tags, ferramentas de navegação, diversidade de resultados e assim por diante.

Trabalhando com python

Vespa é o mecanismo de serviço escalável de código aberto para armazenar, computar e classificar big data no horário de atendimento do usuário. pyvespa fornece uma API python para a Vespa - use-a para criar, modificar, implantar e interagir com instâncias Vespa em execução. O objetivo principal da biblioteca é permitir uma prototipagem mais rápida e facilitar os experimentos de aprendizado de máquina para aplicativos Vespa. pyvespa fornece uma API python para a Vespa. O objetivo principal da biblioteca é permitir prototipagem mais rápida e facilite experimentos de aprendizado de máquina para aplicativos Vespa:

  1. Construir e disponibilizar um aplicativo Vespa usando a API pyvespa.
  2. Conectar para um aplicativo Vespa existente e execute consultas em python.
  3. Importar um pacote de aplicativos Vespa a partir de arquivos e use o pyvespa para acessá-lo.

Para que é utilizada a Vespa

Com a computação de baixa latência em grandes bancos de dados, um novo mundo de possibilidades para novos aplicativos e recursos se abre. Estes são alguns dos problemas mais conhecidos que as pessoas usam a Vespa para resolver:

  • Pesquisa de texto: A Vespa tem um mecanismo de busca de texto completo com suporte total para a recuperação tradicional de informações, bem como técnicas modernas baseadas em incorporação.
  • Recomendação e personalização: Recomendação, personalização de conteúdo e segmentação de anúncios são a mesma coisa quando se trata de implementação: para um determinado usuário ou contexto, avalie modelos de recomendação de conteúdo aprendidos por máquina para encontrar os melhores itens e mostrá-los ao usuário.
  • Resposta de perguntas: A resposta às perguntas fornece respostas diretas à pergunta do usuário.
  • Navegação semiestruturada: Os aplicativos que usam dados semiestruturados, ou seja, uma combinação de bancos de dados, como dados e texto simples, geralmente se beneficiam ao permitir que os usuários naveguem nos dados usando navegação estruturada e pesquisa de texto.
  • Pesquisa pessoal: A pesquisa pessoal serve para fornecer pesquisas em coleções pessoais de dados, nas quais nunca há a necessidade de pesquisar em muitas coleções em uma única consulta.
  • Sugestões de digitação antecipada: qualquer aplicativo que faça uso de entrada textual faz uso de sugestões de digitação antecipada, nas quais várias conclusões sugeridas são apresentadas enquanto o usuário está digitando. Isso geralmente envolve pesquisar e classificar as conclusões de candidatos correspondentes com uma latência muito baixa - um trabalho adequado para a Vespa.

Neste post, vamos nos concentrar em pesquisa de texto com a vespa, então vamos verificar o que a vespa pode fazer por nós.

Pesquisa de texto com Vespa

“O Vespa é um mecanismo de busca de texto completo com suporte total para a recuperação tradicional de informações, bem como técnicas modernas baseadas em incorporação.... essas abordagens podem ser combinadas de forma eficiente no mesmo modelo de consulta e classificação...” Os aplicativos de pesquisa geralmente usam esses recursos da Vespa:

  • Pesquisa de texto completo com suporte para base na posição de palavras combinando e relevânciae operadores avançados, como VARINHA sobre termos de texto.
  • Rápido pesquisa aproximada do vizinho mais próximo (ANN) em espaços vetoriais, com base no algoritmo HNSW.
  • Correspondência de metadados estruturados.
  • Combinando vários dos operadores correspondentes acima livremente na mesma consulta por E e OU.
  • Um grande conjunto de recursos de relevância, incluindo bm25 e recursos de texto mais avançados usando informações posicionais, recursos geográficos, tempo e assim por diante.
  • Classificação por arbitrário expressões matemáticas sobre escalar e tensor recursos, bem como por modelos criados em LightGBM, XGBoost, TensorFlow ou qualquer ferramenta compatível com ONNX. Isso inclui suporte para modelos modernos de linguagem baseados em transformadores, que são avaliados nos nós de conteúdo, como outras expressões de classificação, para escalabilidade.
  • Suporte para Classificação em duas fases.
  • Expondo os dados de qualquer documento nos resultados, com suporte opcional para fragmentos estáticos ou dinâmicos com destaque.
  • Implemente aplicativos específicos interrogação, resultado e processadores de documentos em Java implantado como parte do aplicativo.
  • Agrupamento, desduplicação e agregação em todas as partidas.

Neste tutorial, focaremos na maioria dessas funções da Vespa, deixando a importação de modelos para a Vespa fora do escopo. Agora que sabemos o que é vespa e para que é usada, vamos mergulhar em como implementar rapidamente um sistema de busca de texto usando o pyvespa.

Primeiro de tudo: dados

Neste exemplo de uso pyvespa usaremos dados de produtos da Amazon. Nosso conjunto de dados tem o seguinte formato: como descrição do título brandmain_cat priceembeddings Cinto de aspirador B00002N62Y Eureka 54312-12 Correia de vácuo de reposição Eureka Eureka Amazon Home $4,36 {'valores': [1,3838, 0,5255, -1,0725, -1,11171,... Aspirador de vasilha com fio B00002N8CX Eureka Mighty Mite 3670G... O aspirador de pó Mighty Mite está equipado com... Eureka Amazon Home $12,97 {'valores': [1,79, 0,4431, -0,3274, -1,2027, 1... Algumas coisas a serem levadas em consideração ao tentar fazer upload de dados para o aplicativo vespa: precisamos de um identificador exclusivo para cada linha (nesse caso, será 'asin', que é o identificador do produto) e os dados incorporados devem ser um dicionário com uma chave chamada 'valores' e o valor deve ser o tensor. Antes de importar os dados, eles devem estar no formato json, assim: [{'asin': 'B00002N62Y', 'title': 'Cinto de aspirador de pó Eureka 54312-12', 'category': 'Aspiradores e cuidados com o piso para casa e cozinha', 'description': 'Eureka Replacement Vacuum Belt', 'feature': 'Limite de 1 por pedido As devoluções não serão honradas marcado neste item de encerramento', 'rank': '> #1 .098.930 em Casa e Cozinha (Veja os 100 melhores em Casa e Cozinha) > #17 .327 em Casa e Cozinha > Aspiradores e Cuidados com o Piso', 'brand': 'Eureka', 'main_cat': 'Amazon Home', 'price': '$4,36', 'embeddings': {'values': [1,3838, 0,5255, -1,0725,..., 0. 456, 0.8432, 0.3859]}}] Agora estamos prontos para criar nosso sistema de busca de texto com vespa.

Como implementar rapidamente um sistema de busca de texto usando o pyvespa:

  1. Criar um pacote de aplicativos
  2. Adicionar campos para o esquema
  3. Pesquisar vários campos ao consultar e definir como classificação os documentos corresponderam
  4. Construir o pacote de aplicativos
  5. Implantar o aplicativo vespa
  6. Alimentação e atualização os dados
  7. Consulta o aplicativo de pesquisa de texto usando a linguagem Vespa Query

1. Crie um pacote de aplicativos

Crie um pacote de aplicativos , não use um - no nome: de vespa.package import ApplicationPackage app_package = applicationPackage (name="completePipeline”)

2. Adicionar campos ao esquema

Adicionar campos para o aplicativo esquema: Em termos de dados, a Vespa opera com a noção de documentos. Um documento representa um único item pesquisável em seu sistema, por exemplo, um artigo de notícias, uma foto ou um usuário. Cada tipo de documento deve ser definido na configuração da Vespa por meio de um esquema. Os dados inseridos na Vespa devem corresponder à estrutura do esquema, e os resultados retornados durante a pesquisa também estarão nesse formato. Não há suporte dinâmico à criação de campos na Vespa, pode-se dizer que os esquemas de documentos da Vespa são fortemente digitados. de vespa.package import Document, Field, HNSW products_document = Document (fields= [Field (name = “id”, type = “string”, indexing = ["attribute”, “summary"]), Field (name = “asin”, type = “string”, indexing = ["atributo”, “resumo"], atributo = ['pesquisa rápida', 'acesso rápido']), Campo (nome = “título”, tipo = “string”, indexação = ["índice”, “resumo"], índice = “enable-bm25"), Campo (nome = “descrição”, tipo = “string”, indexação = ["index”, “resumo"], índice = “enable-bm25"), Campo (nome = “marca”, tipo = “string”, indexação = ["atributo”, “resumo"]), Campo (nome = “main_cat”, tipo = “string”, indexação = ["atributo”, “resumo"]), Campo (nome = “preço”, tipo = “string”, indexação = ["atributo”, “resumo"]), Campo (name="embeddings”, type="tensor (<float>x [512])”, indexing= ["attribute”, “index"], ann=HNSW (distance_metric="euclidean”, max_links_per_node=16, neighbors_to_explore_at_insert=500),)]) O documento é encapsulado dentro de outro elemento chamado esquema. Este documento contém vários campos. Cada campo tem um tipo, como string, int ou tensor. Os campos também têm propriedades. Por exemplo, a indexação de propriedades configura o pipeline de indexação de um campo, que define como a Vespa tratará a entrada durante a indexação.

  • índice: Crie um índice de pesquisa para esse campo.
  • atributo: Armazene esse campo na memória como um atributo — para classificação, consultando, ranking e agrupamento.
  • resumo: Permite que esse campo faça parte do resumo do documento no conjunto de resultados.

Aqui, também usamos a propriedade index, que configura parâmetros de como a Vespa deve indexar o campo. Para alguns campos, configuramos o Vespa para configurar um índice compatível com a classificação bm25 para pesquisa de texto. Nós adicionamos o incorporações campo definido para conter um tensor unidimensional de flutuadores de tamanho 512. Armazenaremos o campo como um atributo na memória e criaremos uma ANN índice usando o HNSW algoritmo (mundo pequeno navegável hierárquico).

Algumas informações úteis ao definir um documento:

Correspondência Considere o campo de título do nosso esquema e o documento do produto com o título “Cinto de aspirador de pó Eureka 54312-12”. Na entrada original, o valor do título é uma string composta por até 5 palavras, com um único caractere de espaço em branco entre elas. Como devemos ser capazes de pesquisar esse campo? Para campos de string com índice cujo padrão é correspondência: texto, Vespa se apresenta processamento linguístico da corda. Isso inclui tokenização, normalização e dependente do idioma decorrente da corda. Em nosso exemplo, isso significa que a string acima está dividida em 5 tokens, permitindo que a Vespa combine este documento para:

  • as consultas de termo único, como “Eureka”, “Vacuum” e “Cleaner”,
  • a consulta exata da frase “Cinto de aspirador de pó Eureka 54312-12”,
  • uma consulta com dois ou mais tokens em qualquer ordem (por exemplo, “Eureka Vacuum”).

É assim que todos nós esperamos que a pesquisa normal de texto livre funcione. No entanto, campos de string com indexação:atributos não apoiam correspondência: texto, somente correspondência exata ou correspondência de prefixos. A correspondência exata é o padrão e, como o nome indica, exige que você pesquise o conteúdo exato do campo para obter uma correspondência. Veja os modos de correspondência suportados e as diferenças no suporte entre atributo e índice. Uso de memória Os atributos são armazenados na memória, ao contrário dos campos com índice, nos quais os dados são mantidos principalmente em disco, mas paginados sob demanda e armazenados em cache pelo cache de buffer do sistema operacional. Mesmo com tipos de variação grandes, percebe-se que não é prático definir todos os campos do tipo de documento como atributos, pois isso restringirá fortemente o número de documentos por nó de pesquisa. Quando usar atributos Há vantagens e desvantagens em usar atributos — ele permite a classificação, classificação e agrupamento, mas requer mais memória e não oferece suporte aos recursos match:text. Quando usar atributos depende do aplicativo; em geral, use atributos para:

  1. campos usados para classificação, por exemplo, um carimbo de data/hora da última atualização,
  2. campos usados para agrupamento, por exemplo, categoria e
  3. campos acessados em ranking expressões

Finalmente, todos os campos numéricos e tensores usados na classificação devem ser definidos como atributos. Combinando índice e atributo É possível combinar índice e atributo para o mesmo campo. Nesse caso, podemos classificar e agrupar na categoria, enquanto a pesquisa ou correspondência usará a correspondência de índice com match:text, que tokenizará e reduzirá o conteúdo do campo.

3. Pesquise vários campos ao consultar e defina como classificar os documentos correspondentes

UM Conjunto de campos agrupa campos para pesquisa - ele configura as consultas para procurar correspondências nos títulos e no corpo dos documentos: especifique como classificar os documentos correspondentes definindo um Perfil de classificação. Aqui, o bm25 O perfil de classificação combina as pontuações do BM25 de título e descrição: do vespa.package import Schema, FieldSet, RankProfile products_schema = Schema (name="products”, document=products_document, fieldsets= [fieldSet (name="default”, fields= ["title”, “description"])], rank_profiles= [rankProfile (name="bm25", heranças = “default”, first_phase="bm25 (título) + bm25 (descrição)”), rankProfile (name="nativeRank”, inherits="default”, first_phase="nativeRank (título, descrição)”), rankProfile (name="embedding_similarity”, inherits="default”, first_phase="closen="default” ess (embeddings)”), rankProfile (name="bm25_embedding_similarity”, inherits="default”, first_phase="bm25 (title) + bm25 (description) + closeness (embeddings)”)]) Para o produtos esquema, definimos quatro perfis de classificação. O similaridade de incorporação usa a Vespa proximidade recurso de classificação, que é definido como 1/ (1+ distância) para que os produtos com incorporações mais próximas da incorporação da consulta tenham uma classificação mais alta do que os produtos que estão distantes. O bm25 é um exemplo de um perfil de classificação baseado em termos e bm25_embedding_similaridade combina sinais baseados em termos e semânticos como um exemplo de abordagem híbrida.

4. Crie o pacote do aplicativo

O tensores usados em consultas devem ter seu tipo declarado em um perfil de consulta no pacote do aplicativo. O código abaixo declara a incorporação de texto que será enviada por meio da consulta Vespa. <float>Tem o mesmo tamanho e tipo da incorporação do produto. de vespa.package import applicationPackage, queryProfile, queryProfileType, queryTypeField app_package = applicationPackage (name="myapp”, schema= [products_schema], query_profile=queryProfile (), query_profile_type=queryProfileType (fields= [yTypeField (name="ranking.features.query (embedding_text)”, type="tensor (x [512])”,)]) Aqui definimos o esquema a ser carregado no aplicativo. Neste exemplo, adicionamos somente o esquema de produtos, mas ele pode ser mais de um. Depois de criar o pacote do aplicativo, podemos visualizar os componentes do pacote, como o esquema: print (app_package.get_schema ('products') .schema_to_text) schema products {document products {field id type string {indexing: attribute | summary} field asin type string {indexing: attribute | summary attribute {fast-search fast-access}} field title type string {indexing: index | índice resumido: enable-bm25} descrição do campo tipo string {indexing: index | índice sumário: enable-bm25} campo tipo de marca string {indexing: attribute | summary} field main_cat type string {indexing: attribute | summary} campo preço tipo string {indexing: attribute | summary} field embeddings type tensor <float>(x [512]) {indexing: attribute | index attribute {distance-metric: euclidean} index {hnsw {max-links-per-node: 16 vizinhos para explorar na inserção: 500}}} fieldset default {fields: title, description} k-profile bm25 herda o padrão {first phase {expression: bm25 (title) + bm25 (description)}} rank-profile NativeRank herda o padrão {first phase {expression: nativeRank (title, description)}} rank- profile embedding_similarity herda o padrão {first phase {expression: closeness (embeddings)}} rank-profile bm25_embedding_similarity herda o padrão {first-phase {expression: bm25 (title) + bm25 (description) + closeness (embeddings)}}} Se você decidir criar o aplicativo mais básico diretamente usando os arquivos de configuração da Vespa, você acabará com algo assim: myapp/ ─ schemas │ ─ schema_file.sd ─ services.xml A visualização desses dados pode ajudar você a criar o aplicativo vespa fora do pysvespa com mais rapidez. Isso ocorre porque no exemplo acima, para criar o arquivo_esquema sob o esquemas pasta, você só precisará copiar e colar os dados obtidos do get_schema () e esquema a texto () funções.

5. Implante o aplicativo vespa

O aplicativo de pesquisa de texto com campos, um conjunto de campos para agrupar campos e um perfil de classificação para classificar documentos correspondentes agora está definido e pronto para ser implantado. Implantar app_package na máquina local usando o Docker, sem sair do notebook, criando uma instância do Vespa Docker: importe o sistema operacional do vespa.deployment importe VespaDocker vespa_docker = VespaDocker () app = vespa_docker.deploy (application_package=app_package) aplicativo agora tem um Vespa instância, a ser usada para interagir com o aplicativo. pyvespa fornece uma API para definir pacotes de aplicativos Vespa a partir do python. vespa_docker.deploy exporta arquivos de configuração do Vespa para pasta_disco - passar por elas é uma boa maneira de aprender sobre a configuração da Vespa.

6. Alimente e atualize os dados

Podemos alimentar um lote de dados para conveniência ou alimentação individual pontos de dados para maior controle. Neste post, estaremos alimentando com um lote de dados.

Lote

Dados do feed Precisamos preparar os dados como uma lista de dictos com o id chave contendo um ID exclusivo do ponto de dados e do campos chave contendo um ditado com os campos de dados. batch_feed = [{“id”: product ['asin'], “fields”: product} for idx, product in enumerate (merged_data_json)] Em seguida, alimentamos o lote no esquema desejado usando o feed_batch método. resposta = app.feed_batch (schema="products”, batch=batch_feed) Atualizar dados Da mesma forma que nos exemplos sobre alimentação, podemos atualizar um lote de dados por conveniência ou atualizar pontos de dados individuais para aumentar o controle. Precisamos preparar os dados como uma lista de dictos com o id chave contendo um ID exclusivo do ponto de dados, o campos chave contendo um ditado com os campos a serem atualizados e um opcional criar chave com um valor booleano para indicar se um ponto de dados deve ser criado caso ele não exista (padrão é Falso). batch_update = [{“id”: product ['asin'], # data_id “fields”: product, # campos a serem atualizados “create”: True # Opcional. Crie um ponto de dados se não existir, o padrão é False.} para idx, produto em enumerate (merged_data_json)] Em seguida, atualizamos o lote no esquema desejado usando o update_batch método. resposta = app.update_batch (schema="products”, batch=batch_update)

7. Consulte o aplicativo de pesquisa de texto usando a linguagem Vespa Query

Consulta

Consulte o aplicativo de pesquisa de texto usando o Linguagem de consulta Vespa enviando os parâmetros para o argumento do corpo de aplicativo.consulta: query = {'yql': 'selecione * dos produtos de origem onde userQuery (); ',' query ': 'melhor aspirador',' ranking ':' nativeRank ',' type ':' all ',' hits ': 5} O tipo de consulta padrão está usando tudo, exigindo que todos os termos correspondam ao documento. results = app.query (body=query) print ('Número de documentos recuperados: '+ str (results.number_documents_retrieved)) print ('Número de documentos retornados: '+ str (len (results.hits))) Número de documentos recuperados: 104 Número de documentos retornados: 5 Podemos então recuperar informações específicas da lista de alvos por meio dos results.hits ou acesse toda a resposta da Vespa. [clique em ["fields"] ["documentid"] para obter resultados. hits] ['id:products:products: :B00LUQEWMK', 'id:products:products: :B00HL0L8FS', 'id:products:products: :B00D6CNEQQQ', 'id:products:products: :B00J3031B8', 'id:products:products: :B00J3031B8', 'id:products:products: :B00LERGLR4'] results.hits [1] {'id': 'id:products:products: :B00HL0L8FS', 'relevância': 0.21797787435902613, 'fonte': 'myapp_content', 'campos': {'sddocname': 'produtos', 'documentid': 'id' :products:products: :B00HL0L8FS', 'asin': 'B00HL0L8FS', 'title': 'Aspirador sem saco Dyson Dc40 Animal Upright Best Rate', 'description': 'The Dyson DC40 O aspirador vertical Animal foi projetado para todos os tipos de piso, incluindo carpete, azulejo, vinil e madeira. O DC40 Animal vem com uma mini ferramenta de cabeça de turbina para limpar pêlos de animais de estimação e sujeira de locais apertados e de difícil acesso. Se você gostou das séries DC24, DC25, DC28, DC33, DC35, DC44, com certeza vai adorar essa tecnologia Dyson Radial Root Cyclone com fluxos de ar remodelados para maximizar a potência de sucção. A maioria das avaliações de clientes afirma que este é o aspirador portátil sem saco com a melhor classificação, ainda melhor dos limpadores comerciais verticais, Bosch, Sharp, Riccar e Hepa. Sua cabeça de limpeza autoajustável mantém o contato ideal, mesmo em pisos duros e no interior do carro. A tecnologia Ball All Floors facilita a condução até bordas e pontos apertados. A varinha de liberação instantânea se estende até 5 vezes em comprimento para limpeza de escadas e de alto alcance. Os controles na ponta dos dedos permitem que você desligue instantaneamente a barra de escova motorizada para pisos e tapetes duros ou delicados. O filtro de vida útil lavável captura alérgenos e expele o ar mais limpo. Inclui uma ferramenta combinada com cerdas macias para uma limpeza suave. Ferramenta de escada para remover sujeira e poeira dos cantos e bordas verticais das escadas. Materiais: plástico ABS, metal, componentes eletrônicos. Dimensões: 12,2 polegadas de largura x 13,8 polegadas de profundidade x 42,1 polegadas de altura, Peso: 14,51 libras. Peças incluídas: ferramenta combinada, ferramenta de escada, ferramenta de cabeça de mini turbina. Motor: 200 de potência de sucção/Capacidade: 0,42 galões/Alcance do cabo: 24 pés/Alcance da mangueira: 15,3 pés/Modelo: 22913-02/Peças, acessórios e bolsas Dyson. ',' brand ':' Dyson ',' main_cat ': 'Amazon Home',' price ':' $339,99 '}} Podemos mudar o modo de recuperação de tudo para qualquer: query = {'yql': 'selecione * dos produtos de origem onde userQuery (); ',' query ': 'melhor aspiradora',' ranking ':' nativeRank ',' type ':' any ',' hits ': 5} results = app.query (body=query) print ('Número de documentos recuperados: '+ str (results.number_documents_retrieved) print) ('Número de documentos devolvidos: '+ str (len (results.hits))) [hit ["fields"] ["documentid"] for hit in results.hits] Número de documentos recuperados: 1938 Número de documentos devolvidos: 5 ['id:products:products: :B00LUQEWMK', 'id:products:products: :B00HL0L8FS', 'id:products:products: :B00HL0L8FS', 'id:products:products: :B00HL0L8FS', 'products:products ts:products: :B00ATSRQXW', 'id: products:products: :B0042X5RBI', 'id:products:products: :B007IX0OGC'] Que recuperará e classificará todos os documentos que correspondam a qualquer um dos termos da consulta. Como pode ser visto no resultado, quase todos os documentos corresponderam à consulta. Esses tipos de consultas podem ser otimizados para o desempenho usando a Vespa Fraco e operador de consulta: query = {'yql': 'selecione* dos produtos de origem onde userQuery (); ',' query ': 'melhor aspiradora',' ranking ':' nativeRank ',' type ':' weakAnd ',' hits ': 5} results = app.query (body=query) print ('Número de documentos recuperados: '+ str (results.number_documents_retrieved))) print ('Número de documentos devolvidos: '+ str (len (results.hits))) [hit ["fields"] ["documentid"] for hit in results.hits] Número de documentos recuperados: 1835 Número de documentos devolvidos: 5 ['id:products:products: :B00LUQEWMK', 'id:products:products: :B00HL0L8FS', 'id:products:products: :B00HL0L8FS', 'id:produtos:produtos:: B00ATSRQXW', 'id:products:products: :B0042X5RBI', 'id:products:products: :B007IX0OGC'] Nesse caso, um conjunto muito menor de documentos foi completamente classificado devido ao uso de WeakAnd em vez de qualquer outro e obtivemos os mesmos 5 produtos mais bem classificados. De qualquer forma, os documentos recuperados são classificados pela pontuação de relevância, que nesse caso é fornecida pelo recurso de classificação NativeRank que definimos como o perfil de classificação padrão em nosso arquivo de definição de esquema.

Consulta para incorporação e ANN

Para criar incorporações a partir das consultas, empregaremos um Classificador de frases baseado em Bert do Transformadores HuggingFace biblioteca: dos transformadores, importe BertTokenizer, bertModel tokenizer = BertTokenizer.from_pretraining ('bert-base-uncased') model = bertmodel.from_pretraining ('google/bert_uncased_l-8_h-512_a-8') def query_to_embedding (query): tokens = tokenizer (query, return_tensors="pt”, max_length=100, truncation=True, padding=true) outputs = model (**tokens) embedding_query = outputs [0] .tolist () [0] [0] return embedding_query Aqui, usamos um modelo BERT de tamanho médio com 8 camadas e uma dimensão oculta de 512. Isso significa que a incorporação será um vetor de tamanho 512. A Vespa permite que você carregue modelos criados em LightGBM, XGBoost, TensorFlow ou qualquer ferramenta compatível com ONNX. Para simplificar, decidimos usar nosso modelo bert fora da vespa para este tutorial.

Recuperação do nível de consulta

A consulta abaixo envia a incorporação do texto da consulta (query_to_embedding (texto_consulta)) por meio do ranking.features.query (texto_incorporado) parâmetro e use o Vizinho mais próximo operador de pesquisa para recuperar as 100 frases mais próximas no espaço de incorporação usando a distância euclidiana conforme configurado no HNSW configurações. Os produtos devolvidos serão classificados pela similaridade de incorporação perfil de classificação definido no produtos schema. query_text = 'Aspirador vertical sem toque sem saco Eureka Light Speed 200 - Vermelho' query = {'yql': 'selecione * da frase do produto onde ({targetHits:100} NearestNeighbor (embeddings, embedding_text)); ',' hits ': 5,' query ': query_text, 'ranking.features.query (embedding_text) text)': query_to_embedding (query_text), 'ranking.profile': 'embedding_similarity'} results = app.query (body=query) print ('Número de documentos recuperados: '+ str (results.number_documents_retrieved)) print ('Número de documentos retornados: '+ str (len (results.hits))) [hit ["fields"”] ["ID do documento"] para hit in results.hits] Número de documentos recuperados: 100 Número de documentos devolvidos: 5 ['id:products:products: :B003RL86FU', 'id:products:products: :B00D41LZFQ', 'id:products:products: :B003JKH5MY', 'id:products:products: :B00GAWPRUA', ': produtos: produtos:: B00008OIG6']

Recuperação híbrida em nível de consulta

Além de enviar a incorporação da consulta, podemos enviar a string de consulta (texto_consulta) por meio do interrogação parâmetro e use o ouoperador para recuperar documentos que satisfaçam o operador semântico NearestNeighbor ou o operador baseado em termos Consulta do usuário. Escolhendo tipo igual qualquer significa que o operador baseado em termos recuperará todos os documentos que correspondam a pelo menos um token de consulta. Os documentos recuperados serão classificados pelo perfil de classificação híbrido bm25_embedding_similaridade. query_text = 'Aspirador vertical sem toque sem saco Eureka Light Speed 200 - Vermelho' query = {'yql': 'selecione* da frase do produto em que ({targetHits:100} NearestNeighbor (embeddings, embedding_text))) ou userQuery (); ',' hits ': 5,' query ': query_text,' type ':' any ',' hits ': 5,' query ': query_text,' type ':' any ', ranking.features.query (embedding_text)': query_to_embedding (query_text), 'ranking.profile': 'bm25_embedding_similarity'} results = app.query (body=query) print ('Número de documentos recuperados: '+ str (results.number_documents_retrieved)) print ('Número de documentos retornados: '+ str (len (resultados.hits))) [hit ["fields"] ["documentid"] para obter resultados. hits] Número de documentos recuperados: 1938 Número de documentos devolvidos: 5 ['id:products:products: :B003RL86FU', 'id:products:products: :B00IE3OC1I', 'id:products:products: :B00CTQ8RTY', 'id:products:products: :B00CTQ8RTY', 'id:products:products: :B00CTQ8RTY', 'id:products:products: :B00CTQ8RTY', 'id:products:products: :B00CTQ8RTY', 'id:products:products: :B00CTQ8RTY', 'id:products:products: :B00: produtos:: B00B34TW4M', 'id: produtos: produtos:: B008MM5LRA']

8. Limpeza

vespa_docker.container.stop (tempo limite = 600) vespa_docker.container.remove ()

Considerações finais

Hoje você aprendeu os conceitos básicos da Vespa, desde a criação de um documento até a realização de consultas híbridas usando a consulta como texto e a consulta como tensor. Leve em consideração que o pyvespa se destina a ser usado como uma ferramenta de experimentação para recuperação de informações (IR) e não para criar aplicativos prontos para produção. Portanto, se seu aplicativo exigir uma funcionalidade ou um ajuste fino não disponível no pyvespa, basta criá-lo diretamente usando os arquivos de configuração do Vespa, conforme mostrado em muitos exemplos nos documentos do Vespa. Aqui na Marvik, estamos sempre procurando aplicar esses tipos de soluções inovadoras. Se você quiser saber mais sobre como implementar a Vespa em seu projeto, entre em contato com [email protected] e nós podemos te ajudar.

Toda jornada de IA começa com uma conversa

Vamos conversar
Vamos conversar