3 votes

Réseau de vecteurs denses et similarité du cosinus

Je voudrais stocker un tableau de dense_vector dans mon document mais cela ne fonctionne pas comme pour les autres types de données, par exemple.

PUT my_index
{
  "mappings": {
    "properties": {
      "my_vectors": {
        "type": "dense_vector",
        "dims": 3  
      },
      "my_text" : {
        "type" : "keyword"
      }
    }
  }
}

PUT my_index/_doc/1
{
  "my_text" : "text1",
  "my_vector" : [[0.5, 10, 6], [-0.5, 10, 10]]
}

retours :

'1 document(s) failed to index.',
    {'_index': 'my_index', '_type': '_doc', '_id': 'some_id', 'status': 400, 'error': 
      {'type': 'mapper_parsing_exception', 'reason': 'failed to parse', 'caused_by': 
        {'type': 'parsing_exception', 
         'reason': 'Failed to parse object: expecting token of type [VALUE_NUMBER] but found [START_ARRAY]'
        }
      }
    }

Comment puis-je y parvenir ? Les différents documents auront un nombre variable de vecteurs, mais jamais plus d'une poignée.

De plus, je voudrais ensuite l'interroger en effectuant un cosineSimilarity pour chaque valeur de ce tableau. Le code ci-dessous est la façon dont je le fais normalement lorsque je n'ai qu'un seul vecteur dans le doc.

"script_score": {
    "query": {
        "match_all": {}
    },
    "script": {
        "source": "(1.0+cosineSimilarity(params.query_vector, doc['my_vectors']))",
        "params": {"query_vector": query_vector}
    }
}

Idéalement, j'aimerais avoir la similarité la plus proche ou une moyenne.

7voto

Glen Smith Points 86

En dense_vector s'attend à un tableau de valeurs numériques par document, comme suit :

PUT my_index/_doc/1
{
  "my_text" : "text1",
  "my_vector" : [0.5, 10, 6]
}

Pour stocker n'importe quel nombre de vecteurs, vous pouvez faire de l'option my_vector champ un type "imbriqué" qui contiendrait un tableau d'objets, et chaque objet contient un vecteur :

PUT my_index
{
  "mappings": {
    "properties": {
      "my_vectors": {
        "type": "nested",
        "properties": {
          "vector": {
            "type": "dense_vector",
            "dims": 3  
          }
        }
      },
      "my_text" : {
        "type" : "keyword"
      }
    }
  }
}

PUT my_index/_doc/1
{
  "my_text" : "text1",
  "my_vector" : [
    {"vector": [0.5, 10, 6]}, 
    {"vector": [-0.5, 10, 10]}
  ]
}

EDITAR

Ensuite, pour interroger les documents, vous pouvez utiliser ce qui suit (à partir de ES v7.6.1)

{
  "query": {
    "nested": {
      "path": "my_vectors",
      "score_mode": "max", 
      "query": {
        "function_score": {
          "script_score": {
            "script": {
              "source": "(1.0+cosineSimilarity(params.query_vector, 'my_vectors.vector'))",
              "params": {"query_vector": query_vector}
            }
          }
        }
      }
    }
  }
}

Quelques points à noter :

  • La requête doit être enveloppée dans un fichier de type nested déclaration (en raison de l'utilisation d'objets imbriqués pour stocker les vecteurs)
  • Comme les objets imbriqués sont des documents Lucene distincts, les objets imbriqués sont notés individuellement et, par défaut, le document parent se voit attribuer le score moyen des documents imbriqués correspondants. Vous pouvez spécifier la propriété imbriquée score_mode pour modifier le comportement de notation. Dans votre cas, "max" donnera un score basé sur le plus grand score de similarité en cosinus qui décrit les documents les plus similaires.
  • Si vous êtes intéressé à voir les scores de chaque vecteur imbriqué, vous pouvez utiliser la propriété imbriquée inner_hits .
  • Si quelqu'un est curieux de savoir pourquoi +1.0 est ajouté au score de similarité en cosinus, c'est parce que Cos. Sim. calcule les valeurs [-1,1], mais ElasticSearch ne peut pas avoir de scores négatifs. Par conséquent, les scores sont transformés en [0,2].

0voto

Pierre Mallet Points 2863

En dense_vector est destiné à

stocke des vecteurs denses de float (de documentation ) .... Un champ dense_vectoriel est un champ à valeur unique .

Dans votre exemple, vous voulez indexer plusieurs vecteurs dans la même propriété. Mais comme indiqué dans la documentation, votre champ doit être à valeur unique. Si vous avez plusieurs vecteurs pour votre document, ils doivent être distribués dans des propriétés différentes.

Pas de solution de rechange :(

Vous devez donc dispatcher des vecteurs dans différents champs puis utiliser une boucle dans votre script et garder la valeur la plus adaptée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X