Python V4 client silently skipping objects if property is an object?

I have the following schema:

    client.collections.create(
        schema_name,
        description="A class to store articles with a semantic kicker and searchable author.",
        vectorizer_config=None,
        generative_config=wvcc.Configure.Generative.openai(),
        inverted_index_config=wvcc.Configure.inverted_index(
            index_property_length=True
        ),
        vector_index_config=wvcc.Configure.VectorIndex.hnsw(
            distance_metric=wvcc.VectorDistances.COSINE
        ),
        properties=[
            wvcc.Property(name="app_id", data_type=wvcc.DataType.TEXT), # app generated publicationDay-slug   
            wvcc.Property(name="author", data_type=wvcc.DataType.TEXT), # search/filter
            wvcc.Property(name="category", data_type=wvcc.DataType.TEXT), # search/filter
            wvcc.Property(name="excerpt", data_type=wvcc.DataType.TEXT), # search/filter
            wvcc.Property(name="kicker", data_type=wvcc.DataType.TEXT), # to be vectorized
            wvcc.Property(name="locmentions", data_type=wvcc.DataType.TEXT), # search/filter
            wvcc.Property(name="orgmentions", data_type=wvcc.DataType.TEXT), # search/filter
            wvcc.Property(name="permentions", data_type=wvcc.DataType.TEXT), # search/filter
            wvcc.Property(name="publicationDay", data_type=wvcc.DataType.TEXT), # search/filter
            wvcc.Property(name="slug", data_type=wvcc.DataType.TEXT), # used to generate app_id
            wvcc.Property(name="tag", data_type=wvcc.DataType.TEXT), # search/filter
            wvcc.Property(name="title", data_type=wvcc.DataType.TEXT), # to bevectorized
            wvcc.Property(name="topic", data_type=wvcc.DataType.TEXT), # search/filter
        ]
    )

and I inserting objects such as the following one:

{
  "slug": "reddito-a-ostacoli-la-nuova-guerra-ai-poveri",
  "title": "Reddito a ostacoli, la nuova guerra ai poveri",
  "author": "Roberto Ciccarelli",
  "category": "Lavoro",
  "excerpt": "L’inizio del nuovo anno ha segnato un’altra tappa della guerra ai poveri di chi già nel 2021 ha definito il «reddito di cittadinanza» come un «metadone di stato». Ieri è […]\n",
  "kicker": "Parte l’«assegno di inclusione» che sostituisce il «reddito di cittadinanza»: taglio di 1 miliardo mentre la povertà continua a crescere. Il Workfare di Meloni: tagliare il sussidio e spingere a un lavoro che non c’è. La denuncia dell'Inca e della Cgil Firenze: \"Senza sussidio per formazione e lavoro da 3 mesi. Il governo fa cassa sui più vulnerabili\"",
  "tag": "Il caso",
  "topic": "Il reddito è di base",
  "permentions": "Calderone Meloni Inca",
  "locmentions": "Toscana Italia",
  "orgmentions": "Servizio Orientamento Lavoro del sindacato governo Lega-Cinque Stelle governo Commissione Saraceno Commissione Europea Cgil Firenze Cgil Bankitalia INCHIESTA Workfare Alleanza Istat Inps",
  "publicationDay": "2024-01-02",
  "app_id": "2024-01-02-reddito-a-ostacoli-la-nuova-guerra-ai-poveri",
  "to_vectorize": "Reddito a ostacoli, la nuova guerra ai poveri Parte l’«assegno di inclusione» che sostituisce il «reddito di cittadinanza»: taglio di 1 miliardo mentre la povertà continua a crescere. Il Workfare di Meloni: tagliare il sussidio e spingere a un lavoro che non c’è. La denuncia dell'Inca e della Cgil Firenze: \"Senza sussidio per formazione e lavoro da 3 mesi. Il governo fa cassa sui più vulnerabili\" L’inizio del nuovo anno ha segnato un’altra tappa della guerra ai poveri di chi già nel 2021 ha definito il «reddito di cittadinanza» come un «metadone di stato». Ieri è […]\n",
  "vector": [
    0.6132290363,
    -0.4690446854,
    0.525254786,
    -0.1732118428,
    -0.1457476467,
    -0.1705058962,
    0.1395162344,
    -0.0821041614,
    -0.2188497931,
...
    -0.1206238121,
    -0.0389947817
  ]
}

using the following code:

# new V4 client syntax with explicit open, check and close
client = weaviate.connect_to_local(
    host = "localhost",
    port = 8077,
    headers = {
        "X-OpenAI-Api-Key": openai_key,  #  for generative queries
    }
    ) 
if client.is_ready():
    try:
        with client.batch.dynamic() as batch:
            for item in data:   
                vector = item.pop('vector')  # This removes and returns the vector
                properties = item  # The rest of the data is now in 'properties'         
                batch.add_object(properties=properties, collection=schema_name, vector=vector)
        articles = client.collections.get(schema_name)
        response = articles.aggregate.over_all(
                total_count=True
            )
        print(f"We now have {response.total_count} in the {schema_name} collection")
    finally:
        client.close()

this code resulted in printing I had ZERO objects in my collection. At a closer inspection I realized that one of the properties (category but could have been any other), instead of having a string as a value, wrongly had a dicttionary such as:

"category": {
            "name": "Italia",
            "slug": "italia"
        },

with this anomaly in the data, without any visible error, the collection had ZERO objects inserted.

How should I handle this to identify such errors? Thank you

Hi!

THanks for pointing it out. The error handling part for the pyv4 is not yet documented. (turns out it is

Well, it is in video :slight_smile:

Something like:

# new V4 client syntax with explicit open, check and close
client = weaviate.connect_to_local(
    host = "localhost",
    port = 8077,
    headers = {
        "X-OpenAI-Api-Key": openai_key,  #  for generative queries
    }
    ) 
if client.is_ready():
    try:
        with client.batch.dynamic() as batch:
            for item in data:   
                vector = item.pop('vector')  # This removes and returns the vector
                properties = item  # The rest of the data is now in 'properties'         
                batch.add_object(properties=properties, collection=schema_name, vector=vector)
        articles = client.collections.get(schema_name)
        response = articles.aggregate.over_all(
                total_count=True
            )
        print(f"We now have {response.total_count} in the {schema_name} collection")
        print("Failed Objects", articles.batch.failed_objects)
        print("Failed References", articles.batch.failed_references)
    finally:
        client.close()
1 Like