- 投稿日:2020-10-18T15:52:03+09:00
MySQLでもできる! 全文検索のやり方と条件検索!
はじめに
MySQLで、全文検索ができるって知ってましたか?
今回はMySQLでの全文検索のやり方について簡単に紹介していきます!!【YouTube動画】 MySQL 全文検索 高度な検索のやり方
MySQLの全文検索
全文検索とは、複数の文章群から特定の文字列を検索することです。
全文検索として、grep型とindex型があります。grep型は実行時に中身を走査する方式で、検索対象が大きくなると、速度が低下します。
MySQLでいうとLINKE句を使って、文字列を検索することに相当します。index型はDB登録時にIndexを作成する方式で、メモリ消費が多い代わりに、高速に検索できます。
MySQLで使用する場合は、MATCH句やAGAINST句を使って、検索します。全文検索の実行方法
以下のようにして、全文検索用のインデックスを作成できます。
CREATE FULLTEXT INDEX idx on articles(body);実行するときは、MATCHで検索対象のカラムを決め、AGAINSTで条件を決めます。
SELECT id, title, body FROM articles WHERE MATCH(body) AGAINST ('TEST HOGE')検索モード
AGAINST内で検索モードを指定することができます。
デフォルトでは、Natural Language Modeになります。
- Natural Language Mode
デフォルトで適用されるモードで、OR検索のみを実行します。
ただ、完全一致ではないため、以下のような文字もヒットします。「ありがとう」で検索 -> 「ありがとう」だけでなく、「あり」も検索される
- Boolean Mode
AND, NOT, グルーピングなど高度な検索が可能になります。
実行時は以下のように指定します。SELECT id, title, body FROM articles WHERE MATCH(body) AGAINST ('TEST +HOGE' IN BOOLEAN MODE)
- Natural Language Mode with Query Expansion
1度 Natural Language Modeと同じように検索します。
1度目の結果で、該当する文字周辺にあった文字も記録します。
そして、周辺にあった文字も含めて検索し直すことで、関連語を表示したり、スペルミスを修正することができます。
ただ曖昧検索ができる反面、2度実行するので、結果表示が遅くなります。演算子について (Boolean Mode)
Boolean Modeで使用できる演算子について詳しくみていきます。
何も演算子を付けない場合、OR検索になります。
AGAINST ('TEST HOGE' IN BOOLEAN MODE)+を付けると、AND検索ができるようになります。
AGAINST ('+TEST +HOGE' IN BOOLEAN MODE)NOT検索は-ででき、グルーピングは()で括ります。
AGAINST ('(TEST HOGE) -TE' IN BOOLEAN MODE)完全一致をするには、""で括る必要があります。
AGAINST ('"HOGE"' IN BOOLEAN MODE)まとめ
今回はMySQLの全文検索について紹介しました。
使い所は悩みますが、意外と簡単にできます!MySQL編は一旦ここで終わりですが、他に何か紹介して欲しいことがあれば、ご連絡お願いします!
- 投稿日:2020-10-18T14:10:48+09:00
Visual Studio Code 上で MySQL を操作するための便利な拡張機能
この記事について
この記事では、Visual Studio Code 上で、以下のデータベースに接続して値を確認する方法について解説します。
- MySQL
- Azure SQL Database for MySQL
従来の開発では、
MySQL Workbench
など、コーディングを行う場所とは異なるアプリケーションを並行で起動する事例も多かったと思います。
コーディング中にデータベースにアクセスしたくなり別のアプリを起動・切り替え
というようなことは正直面倒で無駄の時間につながります。
Visual Studio Code のみで、コーディングだけでなく、データベースの値も確認できることは、開発中に複数のアプリケーションを起動・行き来しなければならないというような、ちょっとした面倒を軽減させることが可能です。Visual Studio Code 拡張機能
今回利用する拡張機能は、こちらです。
こちらの拡張機能は Jun Han さんという方が個人で開発されているもののようです。Jun Han さんは、GitHub リポジトリを見るに、Microsoft 社の社員さんのようですね。
※残念ながら、Oracle 社や Microsoft 社など、公式のものはありませんでした。※ちなみに、こちらの拡張機能のライセンス形態が
MIT
ライセンスとなっており、MySQL の GPL v2 ライセンスに違反している可能性があります。
また、こちらの拡張機能については、2019 年 4 月 3 日から更新が行われていないようです。(2020/10/17 現在)Azure SQL Database for MySQL に接続
拡張機能の表示
拡張機能をインストールすると、Visual Studio Code の
エクスプローラータブの中
に MySQL の表示が追加されます。
タブには新しく項目が追加されません。こちら、勘違いしやすいポイントですので、ご注意ください。もし、エクスプローラータブ内に表示がされていない場合は、エクスプローラーの表示項目を確認してください。
表示する項目で、MySQL がチェック ON になっていることを確認します。
SSL ルート証明書のダウンロード
Azure SQL Database for MySQL では、構築時にデフォルトで SSL 接続が強要されるようになっています。
そのため、接続に使用する SSL 証明書をダウンロードします。SSL ルート証明書のダウンロードは、以下の Microsoft Docs を参照してください。
サーバーファイアウォールの設定
SQL Database にはサーバー ファイアウォールの設定があります。
ここで、自身の端末のクライアント IP
からの接続を許可しておく必要があります。
設定していない場合は、事前に設定しておきます。接続プロファイルの作成
エクスプローラーの MYSQL 欄の横にある、+ ボタンを選択します。
あるいは、
[Ctrl] + [Shift] + [P]
(macOS の場合は [Command] + [Shift] + [P]) でコマンドパレットを表示し、MySQL: Add Connection を選択することでも対応可能です。接続先の MySQL サーバー名を入力します。
ログインに使用するユーザー名を入力します。
ログインに使用するユーザー名のパスワードを入力します。
MySQL へ接続するためのポート番号を入力します。
SSL 証明書のパスの入力を求められます。
SSL ルート証明書のダウンロードで予めダウンロードしておいた、BaltimoreCyberTrustRoot.crt.pem
ファイルのパスを入力します。
※画像は macOS で、ダウンロードフォルダに該当ファイルをダウンロードした場合の例値の入力が正常に完了したら、エクスプローラーの MYSQL 欄に新しく接続情報が追加され、以下のように接続ができるようになるはずです。
なお、接続先の Azure SQL Database for MySQL のサーバー、およびサーバー管理者ログイン名については、Azure ポータル上で確認可能です。
クエリ実行
使用するベータベースを選択し、右クリックで New Query を選択します。
SQL タブが表示されるので、クエリを作成していきます。
なお、現在接続している MySQL サーバー、およびデータベースについては、Visual Studio Code 画面下部から確認できます。クエリを作成したら、画面を
右クリック -> Run MySQL Query
または[Ctrl] + [Alt] + [E] (macOS の場合は、[Command] + [option] + [E])
でクエリを実行します。実行結果は別タブで表示されます。
SELECT をはじめ、さまざまなクエリを実行できるため、プログラム側で実行するクエリの実行結果を、同じ Visual Studio Code (しかもタブ移動せずに) 簡単に確認することができます。
- 投稿日:2020-10-18T10:13:30+09:00
SpringBoot+MyBatis+MySQLの初歩
概要
これまでJdbcTemplateの使用経験しかなくMyBatisを使ったことがなかったので、SpringBoot + MyBatis + MySQLを使用してみた。
環境
- macOS Catalina 10.15.7
- Java11
- SpringBoot 2.3.4
- MySQL 8.0
- Gradle
やってみたこと
今回は本の情報がDBに登録されており、それを1件取得、全件表示することにします。
- データベースからID検索し表示
- 全件取得して一覧表示
準備する各種クラス・設定ファイルたち
- build.gradle(こちらの依存関係にMyBatisを追加)
- DB関連:data.sql、schema.sql
- BookFormクラス(入力フォームからの値を受け取る)
- ビュー画面(Thymeleaf使用)
- Bookクラス(DBからの値を受け取るEntityクラス)
- BookDaoインタフェース(DBへ問合せを行うためのインタフェース)
- BookDao.xml(ここにSQLを記載。)
- BookServiceクラス(Daoクラスを呼び出す。)
- BookControllerクラス(ブラウザからのリクエストに応じたビューを返す。状況に応じてserviceクラスを呼び出す。)
なぜか、BookDaoはインタフェースを実装せずともBookServiceクラスから利用できる。裏側でごにょごにょ実装されてServiceクラスから利用できるようになっているらしい。
ディレクトリ構成
- MyBatisはマッピングファイル(XMLファイル)にSQLを書くやり方を採用(アノテーション内にSQLを書くやり方もあり)。マッピングファイルはresorces配下のDaoと同じ階層に配置することで、Dao利用時に自動で読み込んでくれる。
└── src ├── main │ ├── java │ │ └── com │ │ └── example │ │ └── demo │ │ ├── ServletInitializer.java │ │ ├── SpringTestApplication.java │ │ ├── controller │ │ │ └── BookController.java │ │ ├── dao │ │ │ └── BookDao.java │ │ ├── entity │ │ │ └── Book.java │ │ ├── form │ │ │ └── BookForm.java │ │ └── service │ │ └── BookService.java │ └── resources │ ├── application.properties │ ├── com │ │ └── example │ │ └── demo │ │ └── dao │ │ └── BookDao.xml │ ├── data.sql │ ├── schema.sql │ ├── static │ │ └── css │ │ └── style.css │ └── templates │ └── index.html └── test依存関係
dependencies { implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.3' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'mysql:mysql-connector-java' annotationProcessor 'org.projectlombok:lombok' providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' testImplementation('org.springframework.boot:spring-boot-starter-test') { exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' }DBの定義
まずはMySQLでデータベースを作っておく。今回の例でいうとlibrary。
CREATE DATABASE library;下記ファイルを用意すると、SpringBoot起動の度にテストデータを用意してくれる。
schema.sql--booktableがあれば削除 DROP TABLE IF EXISTS booktable; --booktableがなければ新しく作成 CREATE TABLE IF NOT EXISTS booktable( id INT AUTO_INCREMENT, book_name VARCHAR(50) NOT NULL, volume_num INT NOT NULL, author_name VARCHAR(50) NOT NULL, published_date DATE NOT NULL, PRIMARY KEY(id) );data.sql--本のリスト初期データ --idカラムはオートインクリメントなので不要 INSERT INTO booktable (book_name, volume_num,author_name,published_date) VALUES ( 'HUNTER X HUNTER',36,'冨樫義博','2018-10-04'), ( 'ベルセルク',40,'三浦健太郎','2018-09-28'), ( 'ドリフターズ',6,'平野耕太','2018-11-30'), ( '羅生門',1,'芥川龍之介','1915-11-01') ;設定ファイル(application.properties)
接続先に
?serverTimezone=JST
をつけないと上手くいかない。また、mybatis.configuration.map-underscore-to-camel-case=true
により、DBのカラム名がスネークケースであってもJava側ではキャメルケースとして認識してくれる。### データベース接続設定 spring.datasource.url=jdbc:mysql://localhost:3306/library?serverTimezone=JST spring.datasource.username=root spring.datasource.password=password spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver ### スネークケースのDBカラム名をSpringのEntity側ではキャメルケースとして対応付けてくれる。 mybatis.configuration.map-underscore-to-camel-case=true ### 初期化を行うかの指定。 spring.datasource.initialization-mode=always各種クラス
Formクラス
今回は画面からはidのみ受け取るのでフィールドは1個。HTML側のinputタグ内name属性とフィールド名は一致させておく。lombokの機能により、@Dataでセッターゲッターは追記不要。フィールドの型はプリミティブ型の
int
ではなく、参照型(ラッパークラス)のInteger
にするのが良いらしい。ゼロとnullで区別がつくため。BookForm.javapackage com.example.demo.form; import lombok.Data; @Data public class BookForm { private Integer id; }Entityクラス
データベースから取得したデータをいったん格納するオブジェクト。Formクラスにも書いたが、型は参照型が良い。
Book.javapackage com.example.demo.entity; import java.time.LocalDate; import lombok.Data; @Data public class Book { private Integer id; private String bookName; private Integer volumeNum; private String authorName; private LocalDate publishedDate; }Daoインタフェースとマッピングファイル
MyBatisの場合は、インタフェースをつくり@MapperアノテーションをつけることでRepositoryクラスになる。1件検索のメソッドでは、単純に数値だけ渡すよりも、Entityクラス(Bookクラス)を介した方が、マッピングファイルの中で、Entityクラスの各フィールドを柔軟に参照できる。
BookDaopackage com.example.demo.dao; import java.util.List; import org.apache.ibatis.annotations.Mapper; import com.example.demo.entity.Book; @Mapper public interface BookDao { //1件検索 Book findById(Book book); //全件取得 List<Book> findAll(); }【XMLファイルについて】
- ファイル名は対応するDaoと同じにする。
- 配置場所はresorces配下のDaoインタフェースと同じ階層にする。
namespace属性
にはDaoインタフェースの完全修飾クラス名を書く。select要素
にSELECT文を書く。
id属性
にはDaoインタフェースの対応するメソッド名を書く。resultType属性
には検索結果をマッピングするクラス名を書く。今回はBookクラス。parameterType属性
は今回省略。メソッドの引数の型を書くらしい。省略すると、自動で実際の引数の型が判定される。- 下記
findById
では、WHERE句でEntityクラス(Bookクラス)のidフィールドを参照している。BookDao.xml<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.demo.dao.BookDao"> <select id="findById" resultType="com.example.demo.entity.Book"> SELECT id, book_name, volume_num, author_name, published_date FROM booktable WHERE id = #{id} </select> <select id="findAll" resultType="com.example.demo.entity.Book"> SELECT id, book_name, volume_num, author_name, published_date FROM booktable </select> </mapper>Serviceクラス
Daoクラスでも書いたが、1件検索メソッドではEntityクラスのidフィールドに値をセットしている。全件取得はEntityクラスを要素にもつリストを返す。
package com.example.demo.service; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.example.demo.dao.BookDao; import com.example.demo.entity.Book; @Service public class BookService { @Autowired BookDao bookDao; //1件検索 public Book findById(Integer id) { Book book = new Book(); book.setId(id); return this.bookDao.findById(book); } //全件取得 public List<Book> getBookList(){ return this.bookDao.findAll(); } }Controllerクラス
下記では@GetMappingや@PostMappingを使いわけてません。
BookController.javapackage com.example.demo.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import com.example.demo.entity.Book; import com.example.demo.form.BookForm; import com.example.demo.service.BookService; @Controller @RequestMapping("/book") public class BookController { @Autowired BookService bookService; @RequestMapping("/search") public String index(BookForm bookForm, String showList, Model model) { //タイトル model.addAttribute("title", "本屋さん"); //bookform(formクラス)がnullじゃなかったら1件検索 if(bookForm.getId() != null) { Book book = bookService.findById(bookForm.getId()); model.addAttribute("book", book); } //一覧表示ボタンが押されると本一覧をmodelに登録。 if(showList != null) { List<Book> bookList = bookService.getBookList(); model.addAttribute("bookList", bookList); } return "index"; } }画面
th:if
でControllerのModelに登録したオブジェクトがnullかどうかで表示する内容が変わります。index.html<!DOCTYPE HTML> <html xmlns:th="http://www.thymeleaf.org"> <head> <title th:text="${title}">title</title> <link href="/css/style.css" rel="stylesheet"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <p>本屋さん</p> <form action="/book/search" method="post"> <label>ID:<input class="input" type="text" name="id"></label><br> <div><input class="search" type="submit" value="検索"/></div> </form> <form action="/book/search" method="post"> <div><input class="list" type="submit" name="showList" value="一覧表示"/></div> </form> <div th:if="${book} !=null" th:object="${book}"> <table> <tr> <th>ID</th> <th>書籍名</th> <th>巻</th> <th>著者名</th> <th>刊行日</th> </tr> <tr> <td th:text="*{id}">id</td> <td th:text="*{bookName}">書籍名</td> <td th:text="*{volumeNum}">巻</td> <td th:text="*{authorName}">著者名</td> <td th:text="*{publishedDate}">刊行日</td> </tr> </table> </div> <div th:if="${bookList} !=null"> <table> <tr> <th>ID</th> <th>書籍名</th> <th>巻</th> <th>著者名</th> <th>刊行日</th> </tr> <tr th:each="book:${bookList}" th:object="${book}"> <td th:text="*{id}">id</td> <td th:text="*{bookName}">書籍名</td> <td th:text="*{volumeNum}">巻</td> <td th:text="*{authorName}">著者名</td> <td th:text="*{publishedDate}">刊行日</td> </tr> </table> </div> </body> </html>CSSよく分かりません。タグを[type=" "]で区別できたり、table thとスペース区切りで子要素を指定できたりする、ということはわかりました。。。
style.css@charset "UTF-8"; input[type="text"]{ width:70%; border-radius: 5px; padding: 10px; } input[type="submit"].search{ border-radius: 5px; padding: 5px; margin-top: 10px; background-color:#99CCCC; } input[type="submit"].list{ border-radius: 5px; padding: 5px; margin-top: 10px; background-color: #008BBB; color:#FFFFFF } table{ width: 100%; margin-top: 10px; border-collapse: collapse; } table th, table td { border: 1px solid #ddd; padding: 6px; } table th { background-color: #6699FF; }
- 投稿日:2020-10-18T02:14:10+09:00
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) が出た時の対処法
- 投稿日:2020-10-18T00:25:04+09:00
Dockerでやっぱりmysqlの中身プレビュー的なのしたくなっちゃった、、、
状況、、
Dockerで環境構築して、mysqlもコマンドで中入ればみれる、よしよし、、
って思っていたけど、いちいちコマンド叩くの嫌になちゃった、、
そうだ!いいのがあるじゃないか!の共有です!
https://hub.docker.com/_/mysql
方法
- docker-compose.ymlに以下を追加 ※8081は使っていないポートでお願いします、
docker-compose.ymladminer: image: adminer restart: always ports: - 8081:8080
- サービスの再構築コマンド(build)、コンテナ作成してスタート(up)、-d(コンテナに後でコマンドで入れるモードにしたい時に使用)をうつ
$ docker-compose up --build -d
※上記行うとローカルで権限変えたもの元通りになったりするのでご注意ください。
- 投稿日:2020-10-18T00:00:04+09:00
データベースの操作(SQL編)
データベースの操作 ~SQL編~
- SQLの使用方法を知る
- データベースの基本的な操作を理解
- テーブルの基本的な操作を理解
ターミナルでの使用方法
ターミナル# ホームディレクトリに戻る % cd # MySQLに接続 % mysql -u rootSequel Proでの使用方法
Sequel Proを使用してログインする際は、下記のように入力
ターミナルで以下のSQLを実行
ターミナルmysql> CREATE DATABASE sqltest;MySQLで以下のSQL文を実行
ターミナルmysql> SHOW DATABASES;データベースを削除
ターミナルmysql> DROP DATABASE sqltest;データベースを指定
データベースを作成して、選択
ターミナルmysql> CREATE DATABASE sqltest; Query OK, 1 row affected (0.00 sec)コマンドでテーブルを作成
ターミナルmysql> CREATE TABLE goods (id INT, name VARCHAR(255));作成したテーブルを表示
ターミナルmysql> SHOW TABLES;テーブルの構造を確認
ターミナルmysql> SHOW columns FROM goods;カラムを追加
ターミナルmysql> ALTER TABLE goods ADD (price int, zaiko int);カラムを変更
ターミナルmysql> ALTER TABLE goods CHANGE zaiko stock int;カラムを削除
ターミナルmysql> ALTER TABLE goods DROP stock;現場からは以上です!