20200114のJavaに関する記事は4件です。

NLP4J [006-034b] NLP4J で言語処理100本ノック #34 「AのB」の Annotator を作ってみる

改善すべき点

NLP4J [006-034] NLP4J で言語処理100本ノック #34 「AのB」 では「AのB」を抽出する処理を直接コードで書いていました。以下の部分です。

// 「AのB」を探す
String meishi_a = null;
String no = null;

for (Keyword kwd : kwds) {
    if (meishi_a == null && kwd.getFacet().equals("名詞")) {
        meishi_a = kwd.getLex();
    } //
    else if (meishi_a != null && no == null && kwd.getLex().equals("の")) {
        no = kwd.getLex();
    } //
    else if (meishi_a != null && no != null && kwd.getFacet().equals("名詞")) {
        System.err.println(meishi_a + no + kwd.getLex());
        meishi_a = null;
        no = null;
    } //
    else {
        meishi_a = null;
        no = null;
    }
}

このようなキーワード抽出(Annotation)の方法ではロジックの再利用ができません。

Annotator

そこでNLP4Jでは独自にAnnotationを追加できる仕組みであるAnnotatorを用意しています。
仕組みといっても単純で、Interface nlp4j.DocumentAnnotator を実装することです。

上記のロジックをAnnotatorのコードとして用意すると以下のようになります。
「AのB」を単純に文字列として出力して終わりではなく、新しいキーワードとして追加しています。
キーワードの種類を識別できるように「word_nn_no_nn」という識別子(=ファセット: facet)を設定しています。

package nlp4j.annotator;
import java.util.ArrayList;
import nlp4j.AbstractDocumentAnnotator;
import nlp4j.Document;
import nlp4j.DocumentAnnotator;
import nlp4j.Keyword;
import nlp4j.impl.DefaultKeyword;

/**
 * 「名詞の名詞」を「word_nn_no_nn」キーワードとして抽出します。
 * @author Hiroki Oya
 */
public class Nokku34Annotator extends AbstractDocumentAnnotator implements DocumentAnnotator {
    @Override
    public void annotate(Document doc) throws Exception {
        ArrayList<Keyword> newkwds = new ArrayList<>();
        Keyword meishi_a = null;
        Keyword no = null;
        for (Keyword kwd : doc.getKeywords()) {
            if (meishi_a == null && kwd.getFacet().equals("名詞")) {
                meishi_a = kwd;
            } //
            else if (meishi_a != null && no == null && kwd.getLex().equals("の")) {
                no = kwd;
            } //
            else if (meishi_a != null && no != null && kwd.getFacet().equals("名詞")) {
                Keyword kw = new DefaultKeyword();
                kwd.setLex(meishi_a.getLex() + no.getLex() + kwd.getLex());
                kwd.setFacet("word_nn_no_nn");
                kwd.setBegin(meishi_a.getBegin());
                kwd.setEnd(kwd.getEnd());
                kwd.setStr(meishi_a.getStr() + no.getStr() + kwd.getStr());
                kwd.setReading(meishi_a.getReading() + no.getReading() + kwd.getReading());
                newkwds.add(kw);
                meishi_a = null;
                no = null;
            } //
            else {
                meishi_a = null;
                no = null;
            }
        }
        doc.addKeywords(newkwds);
    }
}

これで「AのB」というキーワードを抽出するロジックを切り分けて定義することができました。

Annotator の利用

package nlp4j.nokku.chap4;

import java.util.List;
import nlp4j.Document;
import nlp4j.DocumentAnnotator;
import nlp4j.DocumentAnnotatorPipeline;
import nlp4j.Keyword;
import nlp4j.crawler.Crawler;
import nlp4j.crawler.TextFileLineSeparatedCrawler;
import nlp4j.impl.DefaultDocumentAnnotatorPipeline;
import nlp4j.annotator.Nokku34Annotator;

public class Nokku34b {

    public static void main(String[] args) throws Exception {

        // NLP4Jが提供するテキストファイルのクローラーを利用する
        Crawler crawler = new TextFileLineSeparatedCrawler();
        crawler.setProperty("file", "src/test/resources/nlp4j.crawler/neko_short_utf8.txt");
        crawler.setProperty("encoding", "UTF-8");
        crawler.setProperty("target", "text");

        // ドキュメントのクロール
        List<Document> docs = crawler.crawlDocuments();

        // NLPパイプライン(複数の処理をパイプラインとして連結することで処理する)の定義
        DocumentAnnotatorPipeline pipeline = new DefaultDocumentAnnotatorPipeline();
        {
            // Yahoo! Japan の形態素解析APIを利用するアノテーター
            DocumentAnnotator annotator = new YJpMaAnnotator();
            pipeline.add(annotator);
        }
        {
            // 「名詞の名詞」を「word_nn_no_nn」キーワードとして抽出します。
            Nokku34Annotator annotator = new Nokku34Annotator(); // ←課題34はここだけ
            pipeline.add(annotator); // ←課題34はここだけ
        }
        // アノテーション処理の実行
        pipeline.annotate(docs);

        for (Document doc : docs) {
            for (Keyword kwd : doc.getKeywords("word_nn_no_nn")) {
                System.err.println(kwd.getStr());
            }
        }
    }
}

「AのB」を抽出する処理がたった2行になりました!

 // 「名詞の名詞」を「word_nn_no_nn」キーワードとして抽出します。
 Nokku34Annotator annotator = new Nokku34Annotator();
 pipeline.add(annotator);

このようにすれば、独自のAnnotatorをたくさん定義して、さらに自然言語処理を拡張することができるようになるのです。

結果

彼の掌
掌の上
書生の顔
はずの顔
顔の真中
穴の中

まとめ

NLP4J を使うと、Javaで簡単に自然言語処理ができますね!

プロジェクトURL

https://www.nlp4j.org/
NLP4J_N_128.png


Indexに戻る

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

FreeMarkerでSpring Security JSPタグを使う

やりたいこと

FreeMarker上で、 <security:authorize> などのJSPタグを使いたい。https://vorba.ch/2018/spring-boot-freemarker-security-jsp-taglib.html で紹介されていたことを、自分でも確認したい。

FreeMarkerには元々、JSPタグを使う機能があるらしい。→ 参考URL

環境

  • AdoptOpenJDK 11.0.5
  • Spring Boot 2.2.2.RELEASE
    • Spring Security 5.2.1.RELEASE
    • Embedded Tomcat 9.0.29
  • FreeMarker 2.3.29

依存性

pom.xml
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jsp-api</artifactId>
        </dependency>
    </dependencies>

Spring SecurityのJSPタグ( spring-security-taglibs )およびJSP API( tomcat-jsp-api )が必要なのがポイント。

Java Configクラス

SecurityConfig.java
@Configuration
public class MyFreeMarkerConfig {

    private final FreeMarkerConfigurer freeMarkerConfigurer;

    public MyFreeMarkerConfig(FreeMarkerConfigurer freeMarkerConfigurer) {
        this.freeMarkerConfigurer = freeMarkerConfigurer;
    }

    @PostConstruct
    public void init() {
        freeMarkerConfigurer.getTaglibFactory().setClasspathTlds(
                Collections.singletonList("/META-INF/security.tld"));
    }
}

TLDファイルのパスを指定するのがポイント。

画面の書き方

index.ftlh
<#assign security=JspTaglibs["http://www.springframework.org/security/tags"]/>
<html>
<head>
    <title>Index</title>
    <meta charset="UTF-8">
</head>
<body>
<h1>Index</h1>
<@security.authorize access="isAuthenticated()">
    <p>Hello, <@security.authentication property="principal.username"/>!</p>
</@security.authorize>
<p><a href="/secret">Go to secret page</a></p>
<form action="/logout" method="post">
    <input type="submit" value="Logout">
    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
</body>
</html>

<#assign security=JspTaglibs["http://www.springframework.org/security/tags"]/> でJSPタグを指定する。

タグを使う時は <@security.タグ名 プロパティ名="プロパティ値">

コードの全体像

https://github.com/MasatoshiTada/freemarker-spring-security-sample

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Android] MySQLに接続する(未完)

JDBCダウンロード

AndroidからDBに直接接続できないので、JDBCドライバが必要になる。
MySQLインストール時にしなかった方は、こちらのConnecter/Jというリンクからダウンロード・インストールできる。
https://dev.mysql.com/downloads/

C:\Program Files (x86)\MySQL\Connector J 8.0の階層にmysql-connector-java-8.0.18.jarがあるので、これをビルドパスに追加する。

ビルドパス設定

jarファイルをapp/libsの下に追加。
さらにbuild.gradleに以下を追加。

dependencies {
    compile files('libs/mysql-connector-java-8.0.18.jar)
}

その後、おそらく同期ボタンが出てくるので同期する。

・参考URL
https://qiita.com/icchi_h/items/8ce738ce8511ef69c799

パーミッション

ネットワークを使うのでパーミッションが必要。以下を追加。

<manifest>
    <uses-permission android:name="android.permission.INTERNET" />
</manifest>

MySQLへの接続プログラム

MainActivity.java

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        try {
            //データベースに接続
            Connection con = MySqlConnect.getConnection();
            //ステートメントオブジェクトを作成
            Statement stmt = (Statement) con.createStatement();

            //SQL
            String mySql = "select date from table;";
            ResultSet rs = stmt.executeQuery(mySql);

            while(rs.next()) {
                Toast.makeText(getApplicationContext(), rs.getString("date"), Toast.LENGTH_LONG).show();
            }

            //オブジェクトを解放
            rs.close();
            stmt.close();
            con.close();

        } catch (Exception e) {
        }

MySqlConnect.java

class MySqlConnect{
  static Connection getConnection() throws Exception {
    //JDBCドライバのロード
    Class.forName("com.mysql.jdbc.Driver");
    //各設定
    String url = "jdbc:mysql://ホスト名/db名";
    String user = "user_name";
    String pass = "password";
    //データベースに接続
    Connection con = DriverManager.getConnection(url,user,pass);
    return con;
  }
}

・参考URL
https://qiita.com/ks_513/items/0b286c4932a8e36c672e

困ったところ

現在以下のエラーが発生しており、未完状態である。
ClassLoader referenced unknown path
java.lang.UnsupportedOperationException

ビルドパスの設定、gradleファイルの見直しなど試してみたが突破できなかった。

感想

簡単にできると思っていたが、意外と時間がかかる。
様々なサイトを見たが、非同期処理についてはほとんど書かれていなかったので関係ないとみている。
しかしhttps://qiita.com/ks_513/items/0b286c4932a8e36c672e
の一番下に非同期処理したほうが良いといった旨の記述がされているので、試す価値はありそうだ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

図でもっとわかりやすく学ぶ!!Webアプリケーションの模範的な構造MVCモデルとは?

MCVモデルとは?

Webアプリケーションの開発では、サーブレットクラスJSPファイルを組み合わせて作成します。組み合わせることで効率よく開発することができます。
組み合わせて開発する際に参考にされるのがMVCモデルです。
つまり…
アプリケーションの内部構造のお手本やガイドラインのようなもの。
もう少しちゃんと言うと...
GUIアプリケーションのための模範的な構造です。
サーブレットやJSPによるWebアプリケーションも基本的にGUIアプリケーションです。

MVCモデルにおける開発の3つの要素

MVCモデルは、アプリケーションを3つの要素(モデル、ビュー、コントローラ)に分けて開発します。以下の表に役割をまとめてあります。

要素 役割
モデル(Model) アプリケーションの主たる処理(計算処理など)やデータの格納などを行う
ビュー(View) ユーザーに対して画面の表示を行う
コントローラ(Controller) ユーザーからの要求を受け取り、処理の実行をモデルに依頼し、その結果の表示をビューに依頼する

各要素は担当する役割が決められており、他の要素の役割は担いません。
役割を分担しておくことで、処理の修正や拡張を行う際にどの要素に手を加えたら良いかが明確になり、アプリケーションそのものの保守や拡張を行いやすくなる。

これらの要素が連携してアプリケーションの機能をユーザーに提供します。

WebアプリケーションでのMVCモデルの実現

Untitled Diagram.jpg

コントローラはサーブレットクラスの担当
ユーザーからの要求(リクエスト)を受けて全体の制御を行うコントローラは、サーブレットクラスが担当します。リクエストはJSPファイルでもできますが、コントローラ役には、複雑な制御や、例外処理が求められます。そのような処理はJavaが主体のサーブレットクラスのほうが適しています。

モデルはJavaクラスの担当
ユーザーの要求(検索など)に応える処理や、その処理に関係するデータ(検索語や検索結果)を表すモデルは一般的なJavaクラスが担当します。ここでいう一般的なクラスとは、HttpServletRequestのようなWebアプリケーションに関するクラスやインターフェースを含んでいないクラスのことです。
利点:Webアプリケーションの知識がないプログラマでも、モデル開発に参加できるようになります。

ビューはJSPファイルの担当
出力を行うビューは、HTMLの出力を得意とするJSPファイルが担当します。サーブレットクラスでも出力できますが、println()メソッドを大量に必要とするため処理が煩雑になってしまいます。
利点:JSPファイルはHTMLをそのまま書けるので、Webページのデザイン担当者にJavaの知識がなくてもデザインすることができます。

参考文献

国本大悟『スッキリわかるサーブレット&JSP入門 第2版』株式会社インプレス、2019年

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む