Wednesday, July 25, 2012

AlfrescoとTesseract OCR その2 (メタデータ抽出機能を使ってみた編)

こんにちは!aegifの大谷です。

以前の記事からだいぶ時間が経ってしまいましたが、AlfrescoのOCR連携について、もう少し実用的な例を紹介します。今回は、Alfrescoのメタデータ抽出機能(Metadata Extraction)を利用し、OCRの出力結果文字列をコンテンツの属性に保存し、全文検索できるようにしてみたいと思います。


メタデータ抽出機能って何?


メタデータ抽出機能とは、コンテンツ実体(ファイル)の中身を解析し、コンテンツの属性(メタデータ)にコンテンツ実体から抽出したパラメータを格納する機能です。
例えば、Microsoft Officeファイルは「ドキュメントのプロパティ」として「タイトル」「作成者」「会社名」などの情報を保持していますが、AlfrescoにMicrosoft Officeファイルをアップロードすると、自動的にファイルを解析してこれらの情報を抽出し、コンテンツのしかるべき属性にセットします。

Alfrescoにはデフォルトで多数のファイル形式に対してメタデータ抽出が設定されているので、コンテンツ登録時の属性登録が自動化され、登録の手間が省けます。
今回は、カスタムのメタデータ抽出を定義し、OCR出力文字列をコンテンツの属性にセットします。
(メタデータ抽出に関する詳しい説明はこちらを参照してください)


まずは事前準備


 カスタムのメタデータ抽出を定義する前に、OCRのセットアップを行います。今回も前回と同様、Tesseract OCRを利用します。今回は、以前の記事の手順1から3を実施しておきます。


カスタムのメタデータ抽出を実装する


では実際にカスタムのメタデータ抽出を作成していきます。実際にメタデータ抽出が行われるようにするためには、カスタムメタデータ抽出を実装し、その実装クラスをSpringビーンとしてAlfrescoに登録します。

まず、カスタムメタデータ抽出の実装を行います。メタデータ抽出用のクラスを作成するにあたっては、ベースクラスとしてAbstractMappingMetadataExtracterやTikaPoweredMetadataExtracter等が用意されていますが、今回はApache Tikaが提供するメタデータ抽出も利用するため、TikaPoweredMetadataExtracterを利用します。 拡張時のポイントは以下のとおりです。
  • SUPPORTED_MIMETYPESの設定:今回はtiffのみを対象とするため、image/tiffを設定します。
  • ocrCommand変数の追加:Alfrescoから外部コマンドを実行する仕組みであるRuntimeExecを利用してTesseract OCRをキックするために、RuntimeExec型の変数とsetterを定義します。インスタンスはSpringのDIによってセットされます(後述)。
  • getParserメソッドのOverride:Apache Tikaが提供するTiffParserを決め打ちで返すようにします。
  • extractRawメソッドのOverride:メタデータ抽出ロジックを書きます。今回はApache Tika標準のメタデータ抽出を行ったあと、OCRを実行して結果のテキストをcm:descriptionにセットします。
以下がサンプルコードになります(exceptionハンドリングとかいろいろはしょってますので適宜実装してください)。

TiffOcrMetadataExtractor.java
package jp.aegif.sample.tiffocr;

public class TiffOcrMetadataExtractor extends TikaPoweredMetadataExtracter {

  protected static Log logger = LogFactory.getLog(TiffOcrMetadataExtractor.class);

  private RuntimeExec ocrCommand;

  public static final ArrayList<string> SUPPORTED_MIMETYPES = buildSupportedMimetypes(
    new String[] {"image/tiff"},
    new TiffParser()
  );

  public TiffOcrMetadataExtractor() {
    super(SUPPORTED_MIMETYPES);
  }

  public void setOcrCommand(RuntimeExec ocrCommand) {
    this.ocrCommand = ocrCommand;
  }

  @Override
  protected Parser getParser() {
    return new TiffParser();
  }

  @Override
  protected Map<String, Serializable> extractRaw(ContentReader reader) throws Throwable {
    // Tika標準の抽出を行う
    Map<String, Serializable> rawProperties = super.extractRaw(reader);
    // OCRの出力結果テキストをcm:description属性にセットする
    putRawValue(KEY_DESCRIPTION, getText(reader), rawProperties);

    return rawProperties;
  }

  private String getText(ContentReader reader) throws Throwable {
    // OCRに渡す入出力ファイルを作成
    File sourceFile = TempFileProvider.createTempFile("_ocr", null);
    File targetFile = TempFileProvider.createTempFile("_ocr", ".txt");
    reader.getContent(sourceFile);

    // OCRコマンドに渡すパラメータを設定し、OCRを実行
    Map<String, String> properties = new HashMap<String, String>();
    properties.put("source", sourceFile.getAbsolutePath());
    properties.put("target", targetFile.getAbsolutePath());
    ExecutionResult result = ocrCommand.execute(properties);
    if (!result.getSuccess()) {
      throw new AlfrescoRuntimeException("OCR failed : " + result);
    }

    // 結果の読み出し
    BufferedReader br = null;
    try {
      br = new BufferedReader(new InputStreamReader(new FileInputStream(targetFile), "utf-8"));
      StringBuffer sb = new StringBuffer();
      String s;
      while ((s = br.readLine()) != null) {
        sb.append(s);
      }
      return sb.toString();
    } catch (Exception e) {
      throw e;
    } finally {
      if (br != null) br.close();
      sourceFile.delete();
      targetFile.delete();
    }
  }
}

また、以下のファイルを作成し、メタデータ格納先の属性を指定します。なお、このファイルは上記クラスのクラス名と同じファイル名とし、クラスファイルと同じディレクトリに配置してパッケージングする必要があります(=> TiffOcrMetadataExtractor.javaとTiffOcrMetadataExtractor.propertiesを同じパッケージ以下に作成してください)。

TiffOcrMetadataExtractor.properties
# Namespaces
namespace.prefix.cm=http://www.alfresco.org/model/content/1.0

# Mappings
author=cm:author
title=cm:title
description=cm:description
created=cm:created

上記2ファイルが作成できたら、jarパッケージを作成し、配置します。jarの配置先は、<tomcat_dir>/webapps/alfresco/WEB-INF/lib です。


カスタムメタデータ抽出の定義を追加する


次に、先ほど作成したカスタムメタデータ抽出クラスをAlfrescoに登録するための定義ファイルを作成します。登録にはSpringの仕組みを使うので、Springビーンとしての定義を行う必要があります。ポイントは以下のとおりです。
  • parentの指定:必ずbaseMetadataExtracterを指定します。
  • ocrCommandプロパティの指定:Tesseract OCRをキックするためのコマンドを指定します。
以下が定義ファイルになります。ファイル名の最後が必ず"-context.xml"となるようにします。

tiff-ocr-metadata-extractor-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>


  
    
      
        
          
            
              
                C:/alfresco/ocr.bat
                ${source}
                ${target}
              
            
          
        
        
          1,2,3
        
      
    
  

定義ファイルが作成できたら、<tomcat_dir>/shared/classes/alfresco/extension にコピーします。Alfrescoは起動時に、内部的に指定されている定義ファイルを読み込むのですが、カスタム定義を簡単に登録できるように、デフォルト
でextensionディレクトリ以下に配置された*-context.xmlを読み込むよう設定されています。


実際に使ってみる


以上で設定は全て終わり、あとはAlfrescoを起動して動作確認をするだけです。
Alfrescoを起動したら、以下の手順に従って動作確認してみましょう。

1. ブラウザで http://localhost:8080/share/ にアクセスし、ログインします
2. リポジトリもしくは適当なサイトのドキュメントライブラリにアクセスします
3. テスト用のtiffファイルをアップロードします
4. 以下のように、「説明」プロパティにOCR結果の文字列がセットされていることを確認します(OCR結果がイマイチなのはTesseract OCR&日本語という組み合わせだからですね…)


5. 最後に、全文検索でtiffの内容がヒットするか確認します

以上でテスト完了です!

今回は、AlfrescoとTesseract OCRを連携し、メタデータ抽出機能を使ってOCRの結果をコンテンツのプロパティに格納するサンプルを紹介しました。連携するOCRツールが変わった場合は、ocrCommandプロパティでキックするコマンドをツールにあわせて変更するだけですので、お手持ちのOCRツールがある場合はそちらとの連携も試してみるとよいかもしれません。

Wednesday, July 18, 2012

AlfrescoでPDFファイルのプレビューができない!

こんにちは。大谷です。

Alfrescoにはコンテンツプレビュー機能があるのですが、Alfresco Community 4.0.dでPDFファイルのプレビューが表示されない!という現象に遭遇しました。


プレビューが表示されたりされなかったり…


通常ですと、コンテンツ詳細画面で以下のようなプレビュー画面が表示されます。

ところが、4.0.d以降では、一部のPDFファイルで以下のように1ページ目のサムネイルが表示されるだけになってしまうことがあります。


実は4.0.dでコンテンツ変換の仕組みに大きな変更が…


良く調べてみると、4.0.dからrepository.propertiesに以下のパラメータが追加されていました。
# pdf -> swf using Pdf2swf 1M takes about 30 seconds.
# Using a value of 1.25M (a bit larger that the txt or xlsx) used to create
# the pdf on the way to swf to avoid the second part of a transform failing
content.transformer.Pdf2swf.maxSourceSizeKBytes=1152
ちなみに、swfはAdobe Flashの再生用ファイルフォーマットで、まさにAlfrescoのプレビュー機能(Adobe Flashで実装されています)が利用しているものです。
Alfrescoのプレビュー機能は、様々なコンテンツをswf形式に変換し、それを表示しています。そのコンテンツ変換に際して、4.0.dからサイズによる制限が追加されたようです。


というわけで…


<tomcat_dir>/shared/classes/alfresco-global.properties に以下の1行を追加し、上限サイズを増やすことで、PDFファイルのプレビューを確実に行えるようにします。-1を指定すると、サイズ制限が無効になって必ずプレビュー用ファイルが生成されるよになります。
content.transformer.Pdf2swf.maxSourceSizeKBytes=1152


まとめ


上記の設定を行う事で、PDFファイルプレビューのサイズ制限を変更することができ、晴れて先ほどプレビューできなかったPDFファイルのプレビューが表示されるようになりました!
Alfrescoでは、プレビューに限らず、様々な場所でコンテンツ変換を利用しています。4.0.dでのコンテンツ変換機能の変更についての詳細や、コンテンツ変換機能自体についても今後記事にしていこうと思いますので、引き続きよろしくお願いします。

Wednesday, July 11, 2012

Activitiワークフロー:チュートリアル(パート1)

最近リリースされたAlfresco 4には新しいワークフローエンジンが入っています。「Activiti」というエンジンです。
ActivitiはAlfrescoとは独立したプロジェクトなので、他のアプリケーションと使えます。例えばLiferayでActivitiを使えます。Activitiは独立プロジェクトと言っても、実際にはAlfresco社がスポンサーとなっています。

jBPMと同じく、ActivitiはBPMN言語で書かれたビジネスプロセスを使用できます。
今週のブログポストのパート1では、一番簡単なActivitiワークフローを作る方法を説明します。

まずは、Eclipse Classicバージョン3.7(または3.7以上)をインストールしてください:http://www.eclipse.org/downloads/

そして、Eclipseの中にActivitiプラグインをインストールしてください:
・Eclipseを実行
・「ヘルプ」 → 「新規ソフトウェアのインストール」をクリック
・「追加」をクリック
・「名前」と「ロケーション」のところに、「Activiti BPMN 2.0 designer」と「http://activiti.org/designer/update/」を入力(下記の図通り)
・OKをクリックして、少し待つ
・「Activiti BPMN Designer」にチェックを付ける
・「次へ」をクリック
・依存解析を待つ
・「次へ」をクリック
・ライセンスを了承
・「完了」をクリック
・インストールが行われる
・Eclipseを再起動


では、Alfrescoでこのビジネスプロセスを使ってみましょう:
・Eclipseで、「ファイル」 → 「新規」 → 「その他」 → 「Activiti」 → 「Activiti Project」をクリック
・「次へ」をクリック
・「プロジェクト名」のところに、「nico1」を入力
・「完了」をクリック
・プロジェクトの構成が作成されました。「nico1/src/main/resources/diagrams」フォルダーを開く
・「diagrams」に右クリック、「新規」 → 「その他」 → 「Activiti」 → 「Activiti Diagram」
・「ファイル名」のところに「process1」を入力
・「次へ」をクリック
・「Yes, use a template」と「Pooled Review And Approve Activiti Process」を選択
・「完了」をクリック

4つのノードの図が表示されます。ビジネスプロセスの図です。
図の余白にクリックし、下の「プロパティー」→「処理」→「Id」のところに、「activitiReviewPooled」代わりに「process1」を入力。


これから、Alfrescoでこのビジネスプロセスを使いましょう:
・Alfresco Community 4.0d(またはそれ以上)をインストール
・「Alfresco/tomcat/shared/classes/alfresco/extension」というフォルダーを開く
・その中に、「workflows」という新しいフォルダーを作成
・この「workflows」フォルダーの中に、上記のステップで作成された「process1.bpmn」というファイルをコピー
・「Alfresco/tomcat/shared/classes/alfresco/extension」というフォルダーの中に、「activiti-adhoc-timer-workflow-context.xml.sample」というファイルを「nico1-workflow-context.xml」としてコピー
・この「nico1-workflow-context.xml」を下記のように編集:


    
                
                        
                                
                                        activiti
                                        alfresco/extension/workflows/process1.bpmn
                                        text/xml
                                        false
                                
                        
                
                
                        
                alfresco.messages.nicoWorkflow
                        
                
        



「alfresco.messages.nicoWorkflow」の部分はラベルについてです。「Alfresco/tomcat/shared/classes/alfresco/messages」というフォルダーの中に、下記の内容で「nicoWorkflow.properties」というファイルを作成。

process1.workflow.title=Process 1
process1.workflow.description=Based on pooled review

Alfrescoを再起動

ブラウザで「http://127.0.0.1:8080/share」を開いて、ログイン。
「http://localhost:8080/share/page/start-workflow」を開く。
ワークフローのリストの中に、「Process 1」が表示されています。
Alfrescoにデフォルトで登録されている「pooled
review」と同じように使用できます。

今回は、一番簡単なActivitiワークフローを作る方法を説明しました。
パート2では実践的な説明をする予定です。
Alfrescoを使わない場合は、スタンドアローンActivitiのインストールガイド使い方の記事をご覧ください。
Nicolas Raoul

Friday, June 29, 2012

Ubuntu LinuxでEclipse日本語化

1.EclipseのZIPをダンロード:http://www.eclipse.org/downloads/
2.ユーザホームでZIPを展開
3.Pleiadesをダウンロード:http://mergedoc.sourceforge.jp/
4.Eclipseの「dropins」というフォルダーの中に「pleiades」というフォルダーを作成し、そのpleiadesフォルダーの中にPleiadesを展開
5.Eclipseの「eclipse.ini」というファイルをテキストエディタで開いて、最後に下記の一行を追加:

-javaagent:/home/yamada/p/eclipse/dropins/pleiades/plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar

(yamadaの代わりに、自分のユーザ名を入力)

6.Eclipseを起動。メニューなどが日本語で表示されます!

フォルダー構成一覧:
/home
 /yamada
  /eclipse
    eclipse.ini
    eclipse
    /dropins
     /pleiades
      /features
      /plugins
      ...
    ...
   ...
  ...
ニコラ・ラウル

Wednesday, June 20, 2012

第7回Alfresco勉強会を開催しました。


久々にAlfresco勉強会を開催したのでご報告です。


1つ目は私の「Alfresco CI」と題した発表でした。(スライドはこちら)
AlfrescoのWebScriptを新規作成する際にJenkinsを利用できないだろうかと思い、
強引に環境を構築してみたという内容です。3ヶ月ほど前に作ったスライドと
当時の記憶を呼び起こしつつ話したのでいつも以上にぎこちなかったと思います。
すいませんでした。


2つ目の発表は@to2yの「Alfresco黒魔術カスタマイズ」でした。(スライドはこちら)
開発者寄りなのは私のと同じですが、内容は硬派な感じでした。
SharePoint ProtocolとWebDAVの違いに始まり、
WebDAVを利用するカスタムI/Fを実装した際の内容をまとめたものです。
UIを追加すればAlfresco Shareで利用できるという優れものです。
ぜひ今後、Alfrescoのアドオンサイトに載せてほしいです。


今回は2つとも開発者寄りの話になってしまいましたが、
参加者の方には「xxxしてみた」や「xxxしたいけど行き詰まった」みたいな話を
発表スライドの有無を問わず気軽に喋って頂ければ幸いです。


aegifでは、月に一度のペースでAlfresco勉強会を開催しています。
次回は7/18 (水)に開催予定です。
参加を希望される方はぜひこちらからお申し込みください。

気軽にご参加ください。

@mryoshio

Sunday, June 17, 2012

出遅れ:久しぶりのOC合宿やりました

ごぶさたしてます。
とたにです。

すでに弊社社長、CTOのブログで書かれているので、完全に出遅れたわけですが、
5/24,25でAegifのオープンソースコンサルティング(OC)チームで合宿をしてきました。

出遅れた理由は、合宿で議論した内容自体はオープンにできない、してもあまり意味がないものが多かったことと、食べ物など周辺の情報もすでに先行して書かれているため、かぶってしまう、という八方塞がりな状況だったためです。
とはいえ、せっかく会社で合宿というイベントをやったので、ブログで書くまでが合宿、という先人の言葉にならって強い気持ちで合宿について書きます!

個人的には合宿してすごく有益だったと思ってるのですが、合宿のメリットとかベストプラクティスとかそういう上から目線のまとめについてはいっぱい過去に書かれているのでざっくり省略して、合宿の一番のネックであるみんなで集まることの難しさ、について書こうと思います。

まず一点目ですが、OCチームは30代前半から半ばのメンバが多く、その中には小さい子供を持つメンバもいます。そういうメンバにとっては平日とはいえ泊まりがけで家を空けるというのがなかなか難しく、参加できる日が限られる、また直前にキャンセルも有り得る、という点です。

もう一つは、これは組織としての課題ですが、案件に関わるメンバにとっては合宿の日程が案件作業で空けられない、または空けていたとしても、案件の進捗次第ではやはり直前で参加できなくなる、という可能性がある、という点です。

それぞれ(特に前者は)避けようと思ってもコントロールできない部分なので対策といっても限られてるんですが、合宿を企画するにあたり、「合宿地まで交通の便が良い」ことをとにかく重視しました。移動の時間がそれほどかからず、時間が遅くなっても本数が確保されている、ということが確保されていれば、初日もしくは2日目に日帰りで参加できるから、と思ったからです。

結果としては1名のメンバが子供の体調が理由でキャンセルになってしまいましたが、もう1名のメンバは家族の体調が悪く夜は家に戻る必要があったものの、直前に宿泊から日帰りに切り替えることで合宿に参加してもらえました。

何というか、交通の便大切って、当たり前すぎてえらそうに書くことじゃないのですが、それで参加できる人数が変わると結果合宿自体の成果にも少なからず影響を与えるので、ちゃんと配慮しといてよかった、と思ったのが本音です。

合宿といえば20代の若いメンバのチームがいけてる感じでやるか、40代以上のおじさん世代がやっている印象で、実は30代のメンバ中心のチームで合宿をするということ自体が結構チャレンジングなんじゃないか、という気がしています。(がんがんやってますけど、という人がいたらすいません。)ですが合宿というフォーマットは企画や準備も含めて気に入っているので、今後も定期的にやっていきますよ!ということを表明しておわりたいと思います。

Wednesday, June 6, 2012

Alfrescoのユーザインポート機能を試す

こんにちは。大谷です。
今回はAlfrescoのユーザインポート機能について紹介したいと思います。

新しくAlfrescoを使い始める時や、他の製品からデータを移行する際に、ユーザ情報を一括でインポートしたいという要望をよく伺います。実はこれまでのAlfrescoではユーザインポート機能が提供されておらず、実現するためには複数ユーザ一括インポート用のスクリプト等を書く必要がありましたが、Alfresco4で遂に複数ユーザ一括インポート機能が実装されました。

使い方は簡単。以下の内容のcsvファイルを作り、Alfrescoにアップロードするだけです。
User Name, First Name, Last Name, E-mail Address, , Password,Company, Job Title, Location, Telephone, Mobile, Skype, IM, Google User Name, Address, Address Line 2, Address Line 3, Post Code, Telephone, Fax, Email


必須項目はUser Name(ログインユーザ名),First Name(表示名-名),Last Name(表示名-姓),E-mail Address(メールアドレス)なので、最低限このカラムには情報を入力します。
なお、Passwordを指定すると初期パスワードが設定されます。Passwordを指定しない場合はLast Nameが初期パスワードに設定されるので、Last Nameがマルチバイト文字列の場合はPasswordを指定しておいた方がよいでしょう。

具体的なインポート手順は以下のとおりです。

1. 以下のようなcsvファイルを用意します。
User Name,First Name,Last Name,E-mail Address,,Password,Company,Job Title,Location,Telephone,Mobile,Skype,IM,Google User Name,Address,Address Line 2,Address Line 3,Post Code,Telephone,Fax,Email
nobunaga.oda,信長,織田,nobunaga.oda@aegif.jp,,password1,,,,,,,,,,,,,,,
hideyoshi.toyotomi,秀吉,豊臣,hideyoshi.toyotomi@aegif.jp,,password2,,,,,,,,,,,,,,,
ieyasu.tokugawa,家康,徳川,ieyasu.tokugawa@aegif.jp,,password3,,,,,,,,,,,,,,,


2. adminユーザでログインし、「その他のアクション」->「ユーザー」をクリックします。

3. 「ユーザーCSVファイルのアップロード」をクリックします。

4. 先ほど作成したファイルを選択して「アップロード」をクリックします。

5. 以下の画面が表示されたらユーザインポート完了です。


ただし、注意点が2点ほどあります。
  • "E-mail Address"と"Password"の間のカンマは2つです。
  • 日本語等のマルチバイト文字を使う場合は、csvをUTF-8で保存する必要があります。ExcelでCSV形式に出力するとShift_JISになるので、テキストエディタ等で開いてUTF-8で保存しなおしてください。
 詳しくはこちら(英語です…)に説明が載っていますので参照してください

(2013/07/29追記) 「ユーザーCSVファイルのアップロード」とあるのですが、ここでxls, xlsx形式のファイルをアップロードすることもできるようです。その場合は上記のような文字コードを気にせずともユーザ登録できます。