תוכן ענינים

מבוא

תכנה זאת עוסקת בחילוץ אוטומטי של נתונים מתוך ויקימילון.
ויקימילון הנו פרויקט מילון רב לשוני שנועד לשימושים רבים. הוא מתנהל כפרויקט שיתופי, על בסיס אותם עקרונות של ויקיפדיה.
בהיבט של עיבוד נתונים - ערך בויקימילון מיוצג כטקסט יוניקוד(Unicode) פשוט(plain).
הנחיות הייצוג של ערכים ותכונותיהם בויקימילון מנסחות בפועל חוקי תחביר שעל עורכי המילון לציית להם. חוקים ותבניות אלה מאפשרים להתבונן בערכי המילון בהתבוננות שהיא 'מונחית אובייקטים'. בהתבוננות כזאת - אפשר להשיג עיבוד נוח ויעיל של מבני קלט שכאלה.
התוצאה המצופה מעיבוד כזה היא הגדרת ממשק מול אובייקטים בעלי typeset מוגדר (בפועל – מול תת קבוצה נבחרת מתוך הסט המלא).
התכנה מבצעת פענוח, סינון וטרנספורמציה של ערכי ויקימילון לייצוג בבסיס נתונים בעל אינדקס מילוני מתאים לחיפוש ולשליפה.
מהלך העיבוד מבוסס על הפיכת התבניות הטקסטואליות מהייצוג התחבירי שלהן בויקימילון לאובייקטים בפורמט JSON.

מה אפשר לעשות עם זה?

ויקימילון הינו מקור עשיר ושימושי לצרכים רבים ומגוונים.
עם זאת - האפשרות לעשות בו שימוש ישיר באמצעים מתוכנתים היא מוגבלת מאד.
עיקר הקושי נובע – כאמור - מן הפער בין האופי הטקסטואלי החופשי והפתוח של ייצוגי ויקימילון לבין הדרישה למבניות - שהיא אבן יסוד לכל מהלך של עיבוד אוטומטי ממוחשב. למרות שהייצוג הפנימי של ערכי ויקימילון מוגדר בכללי תחביר – אין כל אמצעי או טכניקה לבקרה על הטקסטים שמוזנים על ידי עורכי המילון. יש אפוא הכרח לפתח אמצעי תוכנה שיאפשרו הפיכת ייצוג המבנים הפנימיים של ויקימילון לתבניות אובייקטים סטנדרטיות שתהיינה קריאות, זמינות, נגישות ונוחות לעיבוד ממוחשב.

תיאור המערכת

רקע

המידע של וויקי מילון נתון בקובץ XML שמכיל את ערכי המילון.
קרן וויקימדיה משחררת עדכון לקובץ זה אחת לכמה זמן.
מכיוון שישנם ערכים שאינם תואמים לכללי הכתיבה במילון וגם מפני שישנם ערכים שהושחתו בזדון – תכנת העיבוד לא תעבוד על כל שחרור שיינתן לה. אולם בכתיבת התכנה הושם דגש רב על מיצוי מידע ככל שרק ניתן מבלי לרדת לטיפול במקרי קצה ספציפיים מדי לשחרור המעובד על ידה. משום כך יש להריץ את תכנת העיבוד כתסריט(script). כלומר כדי להפעיל את תכנת העיבוד על שחרור עתידי יש להבין את עקרונות הפעולה של התכנה. זאת מכיוון שיתכן מצב בו עורך של ערך יכתוב ערך ללא משמעות לסכמת האובייקט, ואף יגרום להשחתה מכוונת.
קיצורו של דבר: רכיב תכנה זה מצפה לקלט תקני ועל מי שמפעיל אותו להיות ער לכך.
בתכנון המערכת הושם דגש על סקאלביליות (Scalability) ויכולת להתמודד עם שינויים עתידיים במבנה המסמכים. לעתים על חשבון מהירות העיבוד.
הרעיון המנחה בשימת דגש זו הוא ההבנה שמהירות העיבוד לא מהווה מדד לביצועים ולתפקוד ואילו פשטות התפעול, והקלות בה ניתן להכניס שינויים למערכת מהוות מדד לאיכות הביצוע של התכנה.
המערכת מבצעת מספר מעברים על מנת להשלים את מיצוי הקלט. זה נובע מהרצון לשמר ייצוג סטנדרטי בכל שלב מבלי לעשות קיצורי דרך ושימוש בייצוגים פרטניים.

רשימת מונחים

מונח הסבר
Page תג המסמן את יחידת העיבוד הבסיסית בקובץ ויקימילון.
title תג המפתח שעל פיו יאתר הדפדפן את הדף המבוקש באתר ויקימילון. תג זה מוכל בתג page.
מאמר ערך מילוני.
כותרת טקסט המתאר תוכן מאמר המופיע בהמשכו.
טבלת ניתוח דקדוקי טבלה המפרטת את הקטגוריות הדקדוקיות של ערך מילוני(פועל, הטיות, שם עצם)

תהליך העיבוד

תהליך העיבוד מורכב מהשלבים הבאים:

  1. קריאת הדף מקובץ הנתונים.
  2. חילוק הדף לכמה "מאמרים" לפי הכותרת.
  3. הסרת חלקים לא רלוונטיים מהמאמרים.
  4. הפיכת המאמרים לHTML
  5. חילוץ מידע מהDOM וכתיבת אובייקט JSON

1. קריאת הדף מקובץ הנתונים.

נכון להיום, קובץ XML המכיל את נתונים וויקימילון תופס נפח של בין 25 ל30 מגה. לכן כדאי לעבד אותו בעיבוד סדרתי, כאשר בכל עיבוד רק החלק הרלוונטי לו נמצא בזיכרון.
יחידת העיבוד הקטנה ביותר שניתן לחלץ ממנה משמעות מילונית רחבה היא ה-page. ה-page מייצג מאמר באתר ויקימילון ובמבנה הפנימי של קובץ הXML הוא מיוצג על ידי התג page.
את תהליך קריאת הדף מקובץ הנתונים מבצעת המחלקה DatabaseFileBuilder, המחלקה קוראת את קובץ הXML שורה אחרי שורה. כאשר page שלם נקרא לתוך הזיכרון מתחיל תהליך עיבוד הדף:
אם הדף הוא מסוג הפניה(redirect) – כלומר הוא מפנה לערך אחר, נוצר מופע של המחלקה RedirectEntry. מופע זה מקבל את מבנה ה-DOM של המסמך ומאפשר להמירו לייצוג JSON.
לייצוג JSON של כניסת הפניה יש שני שדות מסוג מחרוזת:
  1. title – כותרת ההפניה, מילה שממנה רוצים להפנות לערך אחר.
  2. where_to_redirect – הערך אליו רוצים להפנות.

אם הדף הוא מאמר(כלומר הוא לא הפניה אלא ערך מילוני לעצמו):
מתבצע סינון ראשוני של דפים(page) על פי כותרתם. כותרת הדף נמצאת בתגית title.
כאשר התגית מכילה את התו ':' הדף הוא בדרך כלל דף ללא מידע מילוני.
דוגמאות:

<title>מדיה ויקי:Categories</title>
<title>מדיה ויקי:Aboutpage</title>
<title>מדיה ויקי:Edithelppage</title>

אם הדף עבר את הסינון הראשוני, הוא מועבר לעיבוד כמאמרים (עיבוד המתואר בסעיפים 2-3)
דף שאינו ריק מוסב לפורמט JSON (מתואר בסעיף 5) ונכתב לקובץ הoutput בתור שכזה.

2. חלוקת הדף לכמה "מאמרים" לפי הכותרת.

תיאור הבעיה
לכל דף של ויקימילון יש מפתח הנמצא בתגית title – להבדיל מכותרת. על פי רוב ה-title הוא בעברית, אולם ישנם מקרים בהם ה-title הוא באנגלית.
מטרת חלוקת הדף למאמרים היא לאפשר תרגום מאנגלית לעברית. זאת מכיוון שתרגומו של ערך לעברית מתבצע לפי המילה האנגלית.
נמחיש זאת בדוגמה:
הדף שה-title שלו "מלון" יחולק ל3 מאמרים:
  1. מאמר שתרגומו Hotel
  2. מאמר שתרגומו Melon‏‏‏‏
  3. מאמר שתרגומו Dictionary‏‏‏‏
מתקיים כאן קשר 1:M . למילה אחת בעברית אפשריים כמה פירושים שונים באנגלית.
כאשר נרצה לאחזר את הערך Hotel לא נרצה לקבל את המאמר שעוסק בMelon ואו Dictionary אולם כן נרצה לקבל את הערך "אֻשְׁפִּיז" שגם בו מופיעה המחרוזת Hotel כתרגום (אושפיז בלשון חז"ל: מלון).
חלוקת הדף למאמרים
כותרת המאמר מייצגת את הערך שמתואר מתחתיה.
הכותרות של המאמרים בויקימילון, ורק הן, אמורות להיות עטופות בתג H2 או בסימונו הוויקי ==
על כן, הדפים מחולקים למאמרים לפי תגים אלו.
אולם, מכיוון שישנם כותבים שלא מקפידים על כללי הכתיבה, תהליך החלוקה מתעלם מכותרות בעלות ערכים שמסמנים שדות אחרים במאמר מילוני, כמו לדוגמה- כותרות לא מוקפדות כלהלן:
קישורים חיצוניים – שיצוגו הפנימי הוא ==קישורים חיצוניים==
הערות שוליים, כנ"ל.
חלוקת הדף למאמרים נעשית על ידי המתודה getArticles שבמחלקה Article.

3. הסרת חלקים לא רלוונטיים מהמאמרים ועיבוד ראשוני

יצירת מאמר
מאמר נוצר עם כותרת ותוכן טקסטואלי בפורמט וויקי.
בשלב הראשון מנסים לחלץ מהטקסט "ניתוח דקדוקי". זאת היא טבלה שמסווגת קטגוריות דקדוקיות של הערך המילוני(פועל, שם עצם וכו').
לאחר מכן (אם צריך בכלל לעבד את המאמר) מסירים ממנו חלקים שאינם רלוונטיים, מזהים בו תבניות מוכרות ומסבים אותו לHTML (הסבת המאמר לHTML מתוארת בסעיף 4).
חילוץ של "ניתוח דקדוקי"

הרכיב שהופך מתחביר wiki לHTML אינו תומך בטבלאות. "גוש" הניתוח הדקדוקי מופיע במבנה של טבלה. מכיוון שהוא חלק חשוב בערך מילוני יש לחלצו מייצוגו כטבלה ולעבדו. זהו המופע היחיד של טבלת wiki שנתמך בפרויקט.
חילוץ ערכי הטבלה נעשה על ידי פיצולה לפי שורות, הוצאת ערכים מעמודת הערכים ושיוכם למאפיין (property) המתאים לפי שורת ההסבר.
במידה ומאפיין (property) לא מופיע, אובייקט הJSON שמייצג את הניתוח הדקדוקי לא יכלול את אותו המאפיין.

4. הפיכת המאמרים לHTML

המרת הטקסט למבנה HTML נעזרת בביטויים רגולריים על קלט הוויקי והסבתם לייצוגים המקבילים להם בפורמט HTML.
תבניות הייצוג של וויקי שאין להם מקבילות בHTML מוסבות למאפיינים (attributes) פנימיים של אלמנטי HTML כדי שיהיה אפשר לטפל בהם בהמשך העיבוד.
לדוגמה:
תבנית וויקי סוג HTML
==word== הסבה ישירה מWIKI לHTML <h2>word</h2>
'''Bold Text''' <b>Bold Text</b>
{{ת|אנגלית|Hotel}} הצבת סמן לעיבוד בהמשך <span class="translation" data-destinationLanguage="אנגלית">Hotel</span>
{{משלב|ביולוגיה}} <span class="linguisticRegister">[אקולוגיה]</span>
רשימת תבניות הוויקי הנתמכות מופיעה כאן. היא זאת אשר מגדירה את טווח האפשרויות שהפרויקט יכול להגיע אליהן. בפועל השליפה מתבצעת רק על סט מצומצם מתוכן.

5. חילוץ מידע מהDOM וכתיבת אובייקט JSON

לאחר השלמת השלבים שתוארו לעיל ניתן לייצג DOM.
הייצוג נעשה בעזרת הספרייה jSoup.
חילוץ המידע מתבסס על המבנה הקבוע של ערך בויקימילון, במידה והערך אינו במבנה הקבוע של ערך מילוני נעשית התאמה אופטימלית לגשר על פער הייצוג.
לדוגמה: אם לא נמצא תג צפוי H2 בתחילת הערך מצפים ומחפשים H3.
חילוץ המידע נעשה על בסיס תתי הכותרות שמיוצגות על ידי התג H3. מתחת לכל מופע של תג זה אמור להופיע מידע רלוונטי למופע התג. לדוגמה: מתחת לתג H3 שתוכנו "גיזרון" אמור להופיע תוכן הגיזרון.
המידע שחולץ מוצב באובייקט JSON. מבנה מלא של אובייקט JSON מתואר כאן.

איך מריצים

הוראות לubuntu

$ git clone git@github.com:ArnonEilat/HebrewWiktionaryToJson.git
$ ant -f /Path/To/HebrewWiktionaryToJson/nbproject/build-impl.xml -Dnb.internal.action.name=rebuild clean jar
$ java -jar dist/Database_File_Builder.jar
אפשר גם פשוט לפתוח את התקיה כפרויקט של NetBeans.

הוראות לwindows

ההרצה אמורה לעבוד כמו בubuntu.

איך אפשר לעזור

יש לא מעט TODOs בתוך הקוד, וחלקם ממש קלים.
אפשר למצוא אותם בעזרת הרצת הפקודה grep -Ril 'todo' ./ מתוך ספריית הפרוייקט.
Fork me on GitHub