מרבית הפתרונות שפורסמו עד כה הם איטיים או יכולים להניב תוצאות מזויפות במקרים מסוימים. (לא בדקתי את פיקארד, מה שאני מניח שהוא יעבוד כמתוכנן. אבל באופן אישי אני נוטה לרתוע כשאצטרך להקים מכשיר JVM!)
בוא ניגש לבעיה מזווית אחרת:
לפונקציות hash טובות יש מורכבות ~ O (1) לבדיקה. אם אנו יכולים ליצור טבלת hash של ה- QNAME שלנו, אז חיפוש קובץ BAM צריך להיות O (n) במספר הרשומות. מפתחי ה- Python גאים מאוד בפונקציית ה- hash ב- cpython, אז בואו נשתמש בזה:
#! / Usr / bin / env python3import syswith open (sys.argv [1], 'r' ) כקובץ אינדקס: ids = set (l.rstrip ('\ r \ n') עבור l בקובץ index) עבור שורה ב- sys.stdin: qname, _ = line.split ('\ t', 1) אם qname בתעודות : sys.stdout.write (line)
עם ערכת בדיקה המורכבת מקובץ BAM ~ 3GB ו qnames.txt
עם ~ 65,000 ערכים, פועל samtools להציג input.bam | ./idfilter.py qnames.txt לוקח בערך 6.5 שניות בשרת הבדיקה שלי. לשם השוואה, צנרת ה- SAM ל fgrep -f qnames.txt
(באמצעות GNU grep) אורכת כ- 8.5 שניות (אך עשויה להניב תוצאות מזויפות).
(מדוע אולי grep
מניב תוצאות מזויפות? אם יש לך foo
QNAME ב- qnames.txt
, אך קובץ ה- BAM שלך מכיל גם fooX
ו- fooY
, כולם יותאמו על ידי fgrep
. הפיתרון הוא לעגן כל אחד מדפוסי החיפוש שלך בין תחילת השורה לכרטיסייה, למשל ^ foo \ t
, אך אז עליך להשתמש ב grep
סטנדרטי אשר יצטרך לבנות NFA עבור כל תבנית, ולא ב fgrep
אשר מיישם את Aho-Corasick, ו- תהיה סדרי גודל איטיים יותר.)
כתבתי מחדש את סקריפט הפיתון הקטן שלי ב- Rust באמצעות std :: אוספים :: HashMap
לפונקציית ה- hash, ובאמצעות הארגז rust_htslib לקרוא ולכתוב היישר מ- BAM, וזה עוד מהר פי שניים מהפייתון, גם כשקוראים וכותבים BAM. עם זאת, החלודה שלי לא ממש מתאימה לצריכה ציבורית ...