Introduction to Instill-ai
Working on Instill’s pipeline-backend project was like solving a jigsaw ? puzzle—except some pieces kept changing names! My mission? To create a component that could rename JSON fields without creating conflicts. Join me as I share my journey through learning Go, studying Instill’s well-organized docs, and creating a solution that’s now merged and ready to roll! ?
Instill needed a way to rename fields in JSON data structures dynamically. The twist? We had to handle cases where a renamed field might clash with an existing field. Without a conflict resolution system, chaos would reign supreme!
pipeline-backend manages all pipeline resources within Versatile Data Pipeline (VDP) to streamline data from the start component, through AI/Data/Application components and to the end component.
In ? Instill VDP, a pipeline is a DAG (Directed Acyclic Graph) consisting of multiple components.
flowchart LR
s[Trigger] --> c1[OpenAI Component]
c1 --> c2[Stability AI Component]
c1 --> c3[MySQL Component]
c1 --> e[Response]
c2 --> e
A Component serves as an essential building block within a Pipeline.
See the component package documentation for more details.
A pipeline recipe specifies how components are configured and how they are interconnected.
Recipes are defined in YAML language:
variable <span># pipeline input fields</span> output: <span># pipeline output fields</span> component: <component-id>: type: <component-definition-id> task: <task-id> input: <span># values for the input fields</span> condition: <condition> <span># conditional statement to execute or bypass the</span>
To be honest, I was starting to doubt if I could solve this issue, but then Anni dropped the perfect message that kept me going.
Once I got comfortable, ChunHao, who had crafted a JSON schema for this task, gave me the green light? to start coding. And so, the journey began!
The key requirements were:
Armed with coffee☕ and courage?, I got down to coding. Here’s a sneak peek at the core logic:
First, I created a mapping system to track old and new field names. This was key to detecting conflicts.
func mapFields(fields map[string]string) map[string]string { newFieldMap := make(map[string]string) for oldName, newName := range fields { // Check for conflict if _, exists := newFieldMap[newName]; exists { newName += "_conflict" // Add suffix for conflicts } newFieldMap[oldName] = newName } return newFieldMap }
Any time a conflict was detected, the function added "_conflict" to the new name. It’s a simple trick that ensures our JSON fields stay unique and, most importantly, friendly to each other! ✌️
Once the field mappings were in place, the next step was applying them to our JSON data.
func renameFields(data map[string]interface{}, fieldMap map[string]string) map[string]interface{} { renamedData := make(map[string]interface{}) for key, value := range data { newKey := fieldMap[key] renamedData[newKey] = value } return renamedData }
Here’s the logic that applies the mapped names to our JSON data. The result? Our data’s neatly renamed, conflicts resolved, and structure intact. ?
After creating the component dropped the draft PR & got a comment:
After familiarizing myself with Instill's testing methods and learning how to create effective test cases, I proceeded further.
Testing time! ? I wrote tests covering everything from simple renames to complex edge cases with nested JSON fields. Each round of testing led to further refinements.
{ name: "ok - rename fields with overwrite conflict resolution", // Test where renaming conflicts are resolved by overwriting the existing field. // Expected outcome: "newField" holds "value1", overwriting any previous value. }, { name: "ok - rename fields with skip conflict resolution", // Test where conflicts are resolved by skipping the rename if the target field already exists. // Expected outcome: "newField" remains "value2" without overwrite. }, { name: "nok - rename fields with error conflict resolution", // Test with "error" strategy, which should raise an error on conflict. // Expected outcome: Error message "Field conflict." }, // Additional cases for missing required fields and invalid conflict resolution strategy
Here’s where I’d love to share a personal reflection: Testing was the hardest part of this project ??. There were times when I thought, "Is this test even doing what it’s supposed to?"
Gerade in diesem Moment stieß ich auf ein Fusselproblem—
Er wies auf das Problem hin und lieferte sogar die Lösung. Ich musste es nur implementieren, aber es war eine Erinnerung daran, dass selbst die kleinsten Details wichtig sind, damit der Code reibungslos funktioniert.
Sobald ich diese anfänglichen Hürden überwunden hatte, wurde das Testen zu meinem Sicherheitsnetz. Es gab mir die Gewissheit, dass mein Code in verschiedenen Szenarien funktionieren würde ?️♂️. Es hat mir auch gezeigt, dass das Testen nicht nur ein Schritt zum Abhaken ist, sondern eine Möglichkeit, sicherzustellen, dass mein Code zuverlässig und belastbar ist.
Nach Abschluss meiner Tests habe ich meinen Code gepusht, bereit für den Überprüfungsprozess. Unsere CI-Prüfungen (Continuous Integration) bestanden jedoch nicht. Annis Kommentar erinnerte mich sanft daran, meine Testfälle noch einmal zu überprüfen:
„Hey @AkashJana18, könntest du deine Testfälle überprüfen? Unser CI-Check zeigt, dass es hier nicht bestanden wurde. Bitte testen Sie es zuerst lokal, bevor Sie es an die PR weiterleiten. Wann immer Sie Ihren Commit vorantreiben, lösen wir die Prüfungen aus, damit Sie etwaige Probleme erkennen können, bevor unsere Ingenieure Ihren Code überprüfen. Danke!“
Da wurde mir klar, dass ich die Tests vor dem Absenden lokal ausführen musste. ChunHao fügte außerdem hinzu:
"Bitte führen Sie es aus und bestehen Sie es, bevor Sie die Überprüfung anfordern. Führen Sie $ go test ./pkg/component/operator/json/v0/... aus, um es lokal zu überprüfen."
Ich habe die Tests schnell vor Ort durchgeführt, die Probleme identifiziert und behoben.
Ein kleiner Moment des Feierns?
Durch diesen Prozess wurde mir noch mehr bewusst, wie wichtig lokale Tests sind, da dadurch sichergestellt wurde, dass alles solide war, bevor ich es zur Überprüfung einreichte.
Vor der Zusammenführung führte ChunHao eine abschließende Überprüfung durch, nahm ein paar Optimierungen vor, überprüfte das Testrezept und aktualisierte die Dokumentation, um die neuen Änderungen widerzuspiegeln. Vielen Dank an Anni für ihre kontinuierliche Unterstützung während des gesamten Prozesses – es hat einen großen Unterschied gemacht. ?
L'une des plus grandes leçons que j'ai apprises était de savoir comment la collaboration et le mentorat peuvent faire ou défaire un projet. Les modérateurs d'Instill, Anni et ChunHao, m'ont fourni les conseils dont j'avais besoin lorsque j'étais perdu dans la syntaxe Go ou que j'avais du mal à trouver la bonne approche. En travaillant ensemble, nous avons transformé un problème complexe en une solution propre et fonctionnelle.
Je vais être honnête, il y a eu des moments où j’ai eu l’impression d’avoir mordu plus que je ne pouvais mâcher. Mais les encouragements constants d'Anni, combinés aux instructions claires de ChunHao, m'ont permis de rester sur la bonne voie.
Une autre étape pourrait consister à étendre cette approche à d'autres parties du pipeline qui nécessitent une gestion dynamique des noms de champs, car qui n'aime pas un peu d'automatisation⚙️ ?
Grâce à la documentation solide d'Instill, aux conseils de ChunHao et au soutien moral d'Anni, ce projet est devenu une fantastique expérience d'apprentissage. Je suis passé de ne rien savoir de Go à l'implémentation d'une fonctionnalité entièrement fonctionnelle prête pour la production (et j'ai le PR fusionné pour le prouver ?).
Preuve :
以上是从零到合并:在 Go 中构建 JSON 重命名字段组件的详细内容。更多信息请关注PHP中文网其他相关文章!