javax_slr (javax_slr) wrote,
javax_slr
javax_slr

ЖЖ в БД (скрипт на Groovy)

В продолжении темы маленьких скриптов на groovy - еще один.
Предыдущие: Большие письма в Gmail, Упражнение на сложение (LATEX)
Он запихивает ваш ЖЖ в базу данных.
(Зачем это делать тоже ясно - SQL нам расскажет всё о нашем (или чужом) ЖЖ - темы, комменты, таги - насколько фантазии хватит собирать статистику)

Сначало нам надо скачать ЖЖ в XML.
Это сделает чужая утилита - ljdump
Придется установить Питон, открыть IDLE (Python GUI), загрузить туда утилиту и запустить. Всё спросит она сама.

После её пробега у вас будет директория с файлами LXXX - посты и CXXX - комменты.

А на эти XMLи мы и запустим мой скрипт.
В этом виде он использует pure Java, embedded базу данных Hypersonic (HSQLDB), но можно подключиться к любой, конечно же. Только убедитесь, что JDBC driver у вас в classpath.

На примере этого скипта легко увидеть как изящно в груви можно парсить XML.
Только это, конечно же годится именно для скриптов. В энтерпрайзе никто не будет загружать весь XML в память (а будут использовать SAX),и никто не будет напрямую слать SQL (а будет Connection Pool, prepared statement, batch, Hibernate какой нибудь).

Вот скрипт:



import groovy.sql.Sql
import java.sql.Timestamp

def sql = Sql.newInstance("jdbc:hsqldb:file:lj", "sa", "", "org.hsqldb.jdbcDriver")

// delete table if previously created
try { sql.execute("drop table POST")} catch (Exception e) {}
try { sql.execute("drop table COMMENT")} catch (Exception e) {}

// create table
sql.execute('''create table POST (
    id integer not null primary key,
    url varchar(100),
    subject varchar(100),
    text varchar(10000),
    postdate timestamp
)''')

sql.execute('''create table COMMENT (
    id integer not null primary key,
    postid integer,
    user varchar(100),
    subject varchar(100),
    text varchar(10000),
    commentdate timestamp,
    parentcomment integer
)''')

sql.execute(''' alter table COMMENT add constraint c_postid foreign key (postid) references POST (id)
''')

def dir = "D:\\development\\ljdump-1.5.1\\javax_slr\\"
List<File> files = new File(dir).listFiles().findAll { it.name.startsWith("L")  }
files.each {
  record ->
  def event = new XmlSlurper().parse(record)
  int id = Integer.parseInt(event.itemid.text())
  Date d = Date.parse("yyy-MM-dd HH:mm:ss", event.eventtime.text())   //No time zone
  java.sql.Timestamp sqlDate = new java.sql.Timestamp(d.time)
  String url = event.url.text()
  String subject = event.subject.text()
  String text = event.event.text()

  sql.execute("insert into post (id,url,subject, text, postdate) values ($id, $url, $subject,$text,$sqlDate )")

  File commentsFile = new File(dir + record.name.replace('L', 'C'));
  if (commentsFile.exists()) {

    def comments = new XmlSlurper().parse(commentsFile).comment

    comments.each() {
      comment ->
      String state = comment.state.text()
      if (!"D".equals(state)) { // not deleted
        int commentid = Integer.parseInt(comment.id.text())
        String user = comment.user.text()
        String parentIdStr = comment.parentid.text()
        int parentid = 0;
        if (!parentIdStr.isEmpty())
          Integer.parseInt(parentIdStr)
        Date commentDate = Date.parse("yyy-MM-dd HH:mm:ss", comment.date.text().replace('T',' '))   //No time zone
        Timestamp sqlCommentTime = new Timestamp(commentDate.time)
        String commentsubject = comment.subject.text();
        String body = comment.body.text()

        sql.execute("insert into comment (id,user,subject,text,commentdate,parentcomment, postid) values ($commentid,$user, $commentsubject,  $body, $sqlCommentTime, $parentid, $id)")
      }
    }
  }
}
sql.close();



Конечно же его можно улучшить:
1. Сохранять автора поста (Важно, если парсите комьюнити)
2. Сделать чтобы получал директорию с файлами и URL базы данных как аргумент

Можно улучшить схему:
1. Сохранять таги
2. Хранить авторов в отдельной таблице
3. Добавить индексы

Можно добавить директиву @Grab, чтобы не надо было добавлять драйверы в classpath (я пробывал, у меня не получилось :( )

Теперь глянем как это использовать.
Составим список моих постов у которых больше 50 комментов:




@Grab('hsqldb:hsqldb:1.8.0.7')

import groovy.sql.Sql
Sql sql = Sql.newInstance("jdbc:hsqldb:file:lj", "sa", "", "org.hsqldb.jdbcDriver")
sql.eachRow("select subject, url, (select count (*) from comment where postid = mypost.id) as numcom   from POST as mypost order by numcom desc")
        { row -> if (row.numcom>50) println row}


Результат:
[SUBJECT:Что меня бесит, URL:http://javax-slr.livejournal.com/324397.html, NUMCOM:142]
[SUBJECT:1, URL:http://javax-slr.livejournal.com/329453.html, NUMCOM:137]
[SUBJECT:Вступление, URL:http://javax-slr.livejournal.com/55396.html, NUMCOM:91]
[SUBJECT:Альтернативная история, URL:http://javax-slr.livejournal.com/375084.html, NUMCOM:73]
[SUBJECT:Матрица компетентности программиста, URL:http://javax-slr.livejournal.com/229088.html, NUMCOM:69]
[SUBJECT:Источники радости, URL:http://javax-slr.livejournal.com/330862.html, NUMCOM:65]
[SUBJECT:Опросник на общий контекст: флэшмоб, URL:http://javax-slr.livejournal.com/192595.html, NUMCOM:65]
[SUBJECT:Степень двойки, URL:http://javax-slr.livejournal.com/292479.html, NUMCOM:61]
[SUBJECT:ДНК генеалогия, URL:http://javax-slr.livejournal.com/283962.html, NUMCOM:57]
[SUBJECT:Если бы вы жили в ..., URL:http://javax-slr.livejournal.com/387338.html, NUMCOM:55]
[SUBJECT:Рабоче-карьерное, URL:http://javax-slr.livejournal.com/264434.html, NUMCOM:53]
[SUBJECT:Мир тесен., URL:http://javax-slr.livejournal.com/91867.html, NUMCOM:53]
Tags: programming
Subscribe

  • 60 цитат

    Вообще просто линки я даю только в ФБ, но тут уж очень много удачного. Спасибо за расшаривание, gava Все кошки — либертарианцы:…

  • Интересные ссылки

    Вообще то я начал постить интересные ссылки в ФБ, а не тут, но очень не хочется чтобы ЖЖ затух. Поэтому сегодня - здесь: 2013: ГЛАВНЫЕ…

  • Из воспоминаний воевавших женщин

    ДЕВИЧЬЕ НЕВЫНОСИМОЕ Из воспоминаний воевавших женщин из книги Светланы Алексиевич

  • Post a new comment

    Error

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 1 comment