<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Yukun&#039;s Blog &#187; Set</title>
	<atom:link href="http://www.yukun.info/blog/tag/set/feed" rel="self" type="application/rss+xml" />
	<link>http://www.yukun.info</link>
	<description>難しいことは分かりやすく、簡単なことは面白く紹介</description>
	<lastBuildDate>Thu, 26 Jan 2012 03:33:59 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>MySQL: レコードの更新と削除 &#8211; UPDATE、DELETE文</title>
		<link>http://www.yukun.info/blog/2008/11/mysql-update-delete-record.html</link>
		<comments>http://www.yukun.info/blog/2008/11/mysql-update-delete-record.html#comments</comments>
		<pubDate>Sun, 16 Nov 2008 11:01:05 +0000</pubDate>
		<dc:creator>yukun</dc:creator>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[Set]]></category>
		<category><![CDATA[UPDATE]]></category>
		<category><![CDATA[WHERE]]></category>

		<guid isPermaLink="false">http://www.yukun.info/?p=1248</guid>
		<description><![CDATA[前回はレコードの検索クエリの作成方法を扱いましたが、今回は既存のレコードのフィールド値を更新するUPDATE文と、レコードを削除するDELETE文の練習をしてみます。 まず、扱うテーブル内のレコードの一覧を下記に示します &#8230; <a href="http://www.yukun.info/blog/2008/11/mysql-update-delete-record.html">Continue reading <span class="meta-nav">&#8594;</span></a><p><a href="http://www.yukun.info/blog/2008/11/mysql-update-delete-record.html">MySQL: レコードの更新と削除 &#8211; UPDATE、DELETE文</a> is a post from: <a href="http://www.yukun.info">Yukun&#039;s Blog</a></p>
]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.yukun.info/blog/2008/11/mysql-query-select-where-in-like-between.html" title="MySQL: データ検索クエリの基本 - SELECT文、WHERE句、LIKE、IN、BETWEENキーワード - Yukun's Blog">前回はレコードの検索クエリの作成方法</a>を扱いましたが、今回は既存のレコードのフィールド値を更新するUPDATE文と、レコードを削除するDELETE文の練習をしてみます。</p>
<p>まず、扱うテーブル内のレコードの一覧を下記に示します。これは前回と同じです。</p>
<pre>
mysql> SELECT * FROM book_list;
+---------+--------+--------+-------+-----------------------+
| book_id | title  | author | price | comments              |
+---------+--------+--------+-------+-----------------------+
|       1 | book_A | auth_A |  1500 | good, bad, excellence |
|       2 | book_B | auth_B |  2900 | not bad, good         |
|       3 | book_C | auth_C |  1800 | interesting, amazing  |
|       4 | book_D | auth_D |   700 | sad, depress          |
|       5 | book_E | auth_E |  1200 | good, funny           |
|       6 | book_F | auth_C |  3500 | bored, difficult      |
|       7 | book_G | auth_A |   400 | very good!, excellent |
+---------+--------+--------+-------+-----------------------+
</pre>
<h2>UPDATE文でレコードの更新</h2>
<p>それでは試しに、「<em>値段が1000円を超え2000円未満の本を100円値下げする</em>」SQL文を書いてみます。最初は念のため修正するレコードをSELECT文で出力してみます。</p>
<pre>
mysql> SELECT * FROM book_list
    -> WHERE price > 1000
    -> AND price < 2000;
+---------+--------+--------+-------+-----------------------+
| book_id | title  | author | price | comments              |
+---------+--------+--------+-------+-----------------------+
|       1 | book_A | auth_A |  1500 | good, bad, excellence |
|       3 | book_C | auth_C |  1800 | interesting, amazing  |
|       5 | book_E | auth_E |  1200 | good, funny           |
+---------+--------+--------+-------+-----------------------+
</pre>
<p>次に、UPDATE文で上の本を100円値下げしましょう。</p>
<pre>
mysql> UPDATE book_list
    -> SET price = price - 100
    -> WHERE price > 1000
    -> AND price < 2000;
Query OK, 3 rows affected (0.00 sec)
Rows matched: 3  Changed: 3  Warnings: 0
</pre>
<p>上手くいったようですね。UPDATE文の一般構文は以下のようになります。</p>
<blockquote><p><code>UPDATE ＜テーブル名＞<br />
SET ＜更新する列名1＞ = ＜代入する値1＞ [, ＜更新列名2＞ = ＜代入値2＞, ...]<br />
WHERE ＜条件式＞;</code></p></blockquote>
<p>WHERE句は省略可能です。<strong>SET句内のイコール「=」は代入</strong>演算子です（<strong>WHERE句の「=」は等価</strong>演算子）。複数のフィールドを書き換える際はSET句内の個々の代入式をカンマ<strong>「,」で区切り</strong>ます。UPDATE文は条件に合致する<strong>全ての</strong>レコードをSET句で<strong>書き換え</strong>ます。実際に書き変わったか確認してみましょう。</p>
<pre>
mysql> SELECT title, price FROM book_list
    -> WHERE price + 100 > 1000
    -> AND price + 100 < 2000;
+--------+-------+
| title  | price |
+--------+-------+
| book_A |  1400 |
| book_C |  1700 |
| book_E |  1100 |
+--------+-------+
</pre>
<p>確かに、100円値下げしてありますね。</p>
<h2>DELETE文でレコードを削除</h2>
<p>一般構文は、</p>
<blockquote><p><code>DELETE FROM ＜テーブル名＞<br />
WHERE ＜条件式＞;</code></p></blockquote>
<p>です。条件に合致する<strong>全ての</strong>レコードを削除します。</p>
<pre>
mysql> DELETE FROM book_list
    -> WHERE title = 'book_G';
Query OK, 1 row affected (0.00 sec)

mysql> SELECT title FROM book_list;
+--------+
| title  |
+--------+
| book_A |
| book_B |
| book_C |
| book_D |
| book_E |
| book_F |
+--------+
</pre>
<p>確かに、book_Gが削除されていますね。</p>
<h2>リファレンス</h2>
<ul>
<li><a href="http://dev.mysql.com/doc/refman/5.1/en/update.html" title="MySQL :: MySQL 5.1 Reference Manual :: 12.2.12 UPDATE Syntax" target="_blank">MySQL :: MySQL 5.1 Reference Manual :: 12.2.12 UPDATE Syntax</a></li>
<li><a href="http://dev.mysql.com/doc/refman/5.1/en/delete.html" title="MySQL :: MySQL 5.1 Reference Manual :: 12.2.2 DELETE Syntax" target="_blank">MySQL :: MySQL 5.1 Reference Manual :: 12.2.2 DELETE Syntax</a></li>
</ul>
<h4>関連すると思われる記事：</h4>
<ul class="similar-posts">
<li><a href="http://www.yukun.info/blog/2008/11/mysql-query-select-where-in-like-between.html" rel="bookmark" title="2008年11月13日">MySQL: データ検索クエリの基本 &#8211; SELECT文、WHERE句、LIKE、IN、BETWEENキーワード</a></li>
<li><a href="http://www.yukun.info/blog/2008/11/mysql-sort-record-order-by-asc-desc.html" rel="bookmark" title="2008年11月19日">MySQL: レコードを昇順・降順にソートして出力 &#8211; ORDER BY句</a></li>
<li><a href="http://www.yukun.info/blog/2008/11/mysql-insert-into-table-values.html" rel="bookmark" title="2008年11月11日">MySQL: データをテーブルに追加 &#8211; INSERT文、INTO、VALUES句</a></li>
<li><a href="http://www.yukun.info/blog/2008/11/alter-table-add-drop-change-modify.html" rel="bookmark" title="2008年11月7日">MySQL: 既存テーブルの構造の変更 &#8211; ALTER TABLE文、CHANGE COLUMN句</a></li>
<li><a href="http://www.yukun.info/blog/2008/11/mysql-group-by-same-value-field.html" rel="bookmark" title="2008年11月20日">MySQL: 同じ値のフィールドをグルーピング &#8211; GROUP BY句</a></li>
</ul>
<p><!-- Similar Posts took 18.467 ms --></p>
<p><a href="http://www.yukun.info/blog/2008/11/mysql-update-delete-record.html">MySQL: レコードの更新と削除 &#8211; UPDATE、DELETE文</a> is a post from: <a href="http://www.yukun.info">Yukun&#039;s Blog</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.yukun.info/blog/2008/11/mysql-update-delete-record.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python: set型の集合演算で2つのリスト要素を比較</title>
		<link>http://www.yukun.info/blog/2008/08/python-set-list-comparison.html</link>
		<comments>http://www.yukun.info/blog/2008/08/python-set-list-comparison.html#comments</comments>
		<pubDate>Wed, 06 Aug 2008 15:00:46 +0000</pubDate>
		<dc:creator>yukun</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[List]]></category>
		<category><![CDATA[Set]]></category>

		<guid isPermaLink="false">http://trumpcode.yukun.info/?p=316</guid>
		<description><![CDATA[2つのリストの要素を比較する際、リスト型をset型に変えると「-」「&#038;」などの演算子1つで集合演算できます(AND、OR、NOTとか)。 ソースコード #!/usr/bin/python # coding: U &#8230; <a href="http://www.yukun.info/blog/2008/08/python-set-list-comparison.html">Continue reading <span class="meta-nav">&#8594;</span></a><p><a href="http://www.yukun.info/blog/2008/08/python-set-list-comparison.html">Python: set型の集合演算で2つのリスト要素を比較</a> is a post from: <a href="http://www.yukun.info">Yukun&#039;s Blog</a></p>
]]></description>
			<content:encoded><![CDATA[<p>2つのリストの要素を比較する際、リスト型をset型に変えると「-」「&#038;」などの演算子1つで集合演算できます(AND、OR、NOTとか)。</p>
<h3>ソースコード</h3>
<pre>
#!/usr/bin/python
# coding: UTF-8

# リストの比較(by 集合演算)

old_list = ['A', 'B', 'C', 'D', 'E', 'F'] # 古いリスト
new_list = ['A', 'C', 'F', 'G', 'H', 'I'] # 更新された新しいリスト、とする

# 組み込み関数set()を用いて(リストを含む)シーケンス型からset型データを作成
old_set = set(old_list)
new_set = set(new_list)
print 'old_set           ==', old_set
print 'new_set           ==', new_set

# 差集合: old_setの要素からnew_setに含まれる要素を削除した要素集合
# すなわち、old_setをnew_setに更新した際に、削除された要素集合、とみる
print 'old_set - new_set ==', old_set - new_set
print 'len(old_set - new_set) ==', len(old_set - new_set) # 削除された個数

# old_setをnew_setに更新した際に、追加された要素集合、とみる
print 'new_set - old_set ==', new_set - old_set
print 'len(new_set - old_set) ==', len(new_set - old_set) # 追加された個数

# old_setをnew_setの共通要素集合(更新した際に変更されなかった要素、とみる)
print 'new_set &#038; old_set ==', new_set &#038; old_set

# old_setかnew_setに含まれる要素集合
print 'new_set ^ old_set ==', new_set ^ old_set

# 和集合: old_setとnew_setに含まれる重複の無い要素集合
print 'new_set | old_set ==', new_set | old_set
</pre>
<h3>実行結果</h3>
<pre>
old_set           == set(['A', 'C', 'B', 'E', 'D', 'F'])
new_set           == set(['A', 'C', 'G', 'F', 'I', 'H'])
old_set - new_set == set(['B', 'E', 'D'])
len(old_set - new_set) == 3
new_set - old_set == set(['I', 'H', 'G'])
len(new_set - old_set) == 3
new_set &#038; old_set == set(['A', 'C', 'F'])
new_set ^ old_set == set(['B', 'E', 'D', 'G', 'I', 'H'])
new_set | old_set == set(['A', 'C', 'B', 'E', 'D', 'G', 'F', 'I', 'H'])
</pre>
<p>リスト(and シーケンス型)をset型に変更すると要素の順序が失われます。再度リスト型に戻したいときは、list()関数を用います。</p>
<pre>
&gt;&gt;&gt; set_data = set([&#039;a&#039;, &#039;b&#039;, &#039;c&#039;, &#039;d&#039;])
&gt;&gt;&gt; set_data
set([&#039;a&#039;, &#039;c&#039;, &#039;b&#039;, &#039;d&#039;])
&gt;&gt;&gt; list_data = list(set_data)
&gt;&gt;&gt; list_data
[&#039;a&#039;, &#039;c&#039;, &#039;b&#039;, &#039;d&#039;]
&gt;&gt;&gt; type(list_data)
&lt;type &#039;list&#039;&gt;
&gt;&gt;&gt;
</pre>
<p>話変わりますが、Rubyだと配列のまま加減算ができます(配列オブジェクトが「+」「-」演算子などをサポートしているみたい)。</p>
<h3>リファレンス</h3>
<ul>
<li><a href="http://docs.python.org/lib/types-set.html" title="3.7 Set Types -- set, frozenset" target="_blank">3.7 Set Types &#8212; set, frozenset</a></li>
<li><a href="http://docs.python.org/lib/module-sets.html" title="5.7 sets -- Unordered collections of unique elements" target="_blank">5.7 sets &#8212; Unordered collections of unique elements</a></li>
</ul>
<h4>関連すると思われる記事：</h4>
<ul class="similar-posts">
<li><a href="http://www.yukun.info/blog/2008/06/python-list.html" rel="bookmark" title="2008年6月1日">Python: リストの初期化・出力・代入・要素数</a></li>
<li><a href="http://www.yukun.info/blog/2008/06/python-list-comprehension.html" rel="bookmark" title="2008年6月16日">Python: リスト内包表記(リストコンプリヘンション)をfor文に書き換える</a></li>
<li><a href="http://www.yukun.info/blog/2008/08/python-if-for-in.html" rel="bookmark" title="2008年8月2日">Python: if/for文でのin演算子の各オブジェクト毎の評価</a></li>
<li><a href="http://www.yukun.info/blog/2008/06/python-sequence.html" rel="bookmark" title="2008年6月2日">Python: リストの抽出・連結・要素の追加</a></li>
<li><a href="http://www.yukun.info/blog/2008/06/python-list2.html" rel="bookmark" title="2008年6月12日">Python: リストの要素の追加と削除、取出し &#8211; append()、extend()、pop()、remove()メソッド</a></li>
</ul>
<p><!-- Similar Posts took 7.675 ms --></p>
<p><a href="http://www.yukun.info/blog/2008/08/python-set-list-comparison.html">Python: set型の集合演算で2つのリスト要素を比較</a> is a post from: <a href="http://www.yukun.info">Yukun&#039;s Blog</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.yukun.info/blog/2008/08/python-set-list-comparison.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>検索エンジンを実装 (6)NOT演算</title>
		<link>http://www.yukun.info/blog/2008/06/java-subtraction.html</link>
		<comments>http://www.yukun.info/blog/2008/06/java-subtraction.html#comments</comments>
		<pubDate>Tue, 03 Jun 2008 15:00:00 +0000</pubDate>
		<dc:creator>yukun</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Search Engine]]></category>
		<category><![CDATA[Set]]></category>

		<guid isPermaLink="false">http://www.yukun.info/trump/19700101/java%e3%81%a7%e5%85%a8%e6%96%87%e6%a4%9c%e7%b4%a2%e3%82%a8%e3%83%b3%e3%82%b8%e3%83%b3%e3%82%92%e6%a7%8b%e7%af%89-6not%e6%bc%94%e7%ae%97-building-a-full-text-search-engine-on-java-6subtraction-al</guid>
		<description><![CDATA[今回は集合演算のNOT演算ついて紹介します。この処理は、例として検索の際に「sky NOT rain」と指定すると、&#8221;sky&#8221;というキーワードを含むページから&#8221;rain&#8221;を &#8230; <a href="http://www.yukun.info/blog/2008/06/java-subtraction.html">Continue reading <span class="meta-nav">&#8594;</span></a><p><a href="http://www.yukun.info/blog/2008/06/java-subtraction.html">検索エンジンを実装 (6)NOT演算</a> is a post from: <a href="http://www.yukun.info">Yukun&#039;s Blog</a></p>
]]></description>
			<content:encoded><![CDATA[<p>今回は集合演算のNOT演算ついて紹介します。この処理は、例として検索の際に「sky NOT rain」と指定すると、&#8221;sky&#8221;というキーワードを含むページから&#8221;rain&#8221;を含むページを除きます。</p>
<h3>NOT演算処理の概要</h3>
<p><a href="http://www.yukun.info/wp-content/uploads/subtraction.gif"><img src="http://www.yukun.info/wp-content/uploads/subtraction-e1269626228977.gif" alt="NOT演算結果" title="subtraction" width="400" height="125" class="size-full wp-image-1476" /></a></p>
<p>上の図から、ある2つの語の転置インデックスリストをA, Bとします。ここで、リスト要素をそれぞれa, b(整数)とし演算結果を格納するリストをCとするとき、NOT演算は主に以下の処理内容を繰り返します。</p>
<ol>
<li>if a < b then 要素aをCの末尾に追加し、aにリストAの次の要素を代入</li>
<li>if a = b then A, Bが指す次の要素をa, bに代入</li>
<li>if a > b then bにリストBの次の要素を代入</li>
</ol>
<h3>ソースコード</h3>
<p>今回はNOT演算処理を行う部分(メソッド)のみを示します。後で示す実行結果は、<a href="http://www.yukun.info/blog/2008/05/java-intersection.html" title="検索エンジンを実装 (4)AND演算">前のブログラム</a>をベースにintersect()メソッドの挿入箇所を今回のものに置き換えたものです。</p>
<pre>
import java.util.ArrayList;
/**
 * 検索エンジンのNOT演算
 */
public class BooleanRetrieval {
  /**
   * NOT演算処理
   * @param postsSet 全ての検索語の転置インデックスリスト
   * @return 演算後の転置インデックスリスト
   */
  public static ArrayList&lt;integer&gt; subtract(ArrayList&lt;arrayList&lt;integer&gt;&gt; postsSet) {
    ArrayList&lt;integer&gt; result; // 最終演算結果
    if (postsSet == null) return null;
    int len = postsSet.size();
    if (len == 0) return null;
    else if (len == 1) return postsSet.get(0);
    result = postsSet.get(0);
    for (int i = 1; i &lt; len; i++) {
      result = subtract(result, postsSet.get(i));
    }
    return result;
  }

  public static ArrayList&lt;integer&gt; subtract(ArrayList&lt;integer&gt; p1, ArrayList&lt;integer&gt; p2) {
    ArrayList&lt;integer&gt; answer = new ArrayList&lt;integer&gt;(); // 2語の演算結果
    int len1 = p1.size();
    int len2 = p2.size();
    int i=0, j=0;
    while (i&lt;len1 &amp;&amp; j&lt;len2) {
      int diff = p1.get(i) - p2.get(j);
      if (diff == 0) {
        i++; j++;
      } else if (diff &lt; 0) {
        answer.add(p1.get(i));
        i++;
      } else {
        j++;
      }
    }
    while (i&lt;len1) { answer.add(p1.get(i++)); }
    while (j&lt;len2) { answer.add(p2.get(j++)); }
    return answer;
  }
}
</pre>
<h3>NOT演算の実行結果</h3>
<pre>単語          freq, docID
15           : 1, [2]
5            : 1, [2]
After        : 1, [1]
As           : 1, [1]
I            : 3, [0, 1, 2]

＜中略＞

that         : 1, [2]
the          : 3, [0, 1, 2]
think        : 3, [0, 1, 2]
this         : 1, [2]
time         : 2, [0, 2]
to           : 2, [0, 1]
touch        : 1, [1]
tremendously : 1, [1]
uncertainty  : 1, [1]
use          : 1, [2]
vigorous     : 1, [1]
wanna        : 1, [1]
well         : 1, [1]
what         : 1, [0]
when         : 1, [1]
where        : 1, [0]
why          : 1, [1]
with         : 1, [1]
検索語: the think
結果　:文書中に存在しません。
検索語: the use
結果　:文書ID [0, 1]に存在します。
検索語: the to
結果　:文書ID [2]に存在します。
検索語: quit</pre>
<p>おー、けっこうたのしくなってきましたねー。</p>
<h4>関連すると思われる記事：</h4>
<ul class="similar-posts">
<li><a href="http://www.yukun.info/blog/2008/05/java-union.html" rel="bookmark" title="2008年5月27日">検索エンジンを実装 (5)OR演算</a></li>
<li><a href="http://www.yukun.info/blog/2008/05/java-intersection.html" rel="bookmark" title="2008年5月20日">検索エンジンを実装 (4)AND演算</a></li>
<li><a href="http://www.yukun.info/blog/2008/03/java-ngram.html" rel="bookmark" title="2008年3月7日">検索エンジンを実装 (1)転置インデックス作成</a></li>
<li><a href="http://www.yukun.info/blog/2008/03/java-ngram-2.html" rel="bookmark" title="2008年3月16日">検索エンジンを実装 (2)出現位置とその文書ID</a></li>
<li><a href="http://www.yukun.info/blog/2008/03/java-ngram-3.html" rel="bookmark" title="2008年3月23日">検索エンジンを実装 (3)文書内の検索語を特定</a></li>
</ul>
<p><!-- Similar Posts took 9.047 ms --></p>
<p><a href="http://www.yukun.info/blog/2008/06/java-subtraction.html">検索エンジンを実装 (6)NOT演算</a> is a post from: <a href="http://www.yukun.info">Yukun&#039;s Blog</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.yukun.info/blog/2008/06/java-subtraction.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>検索エンジンを実装 (5)OR演算</title>
		<link>http://www.yukun.info/blog/2008/05/java-union.html</link>
		<comments>http://www.yukun.info/blog/2008/05/java-union.html#comments</comments>
		<pubDate>Mon, 26 May 2008 15:00:00 +0000</pubDate>
		<dc:creator>yukun</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Search Engine]]></category>
		<category><![CDATA[Set]]></category>

		<guid isPermaLink="false">http://www.yukun.info/trump/19700101/java%e3%81%a7%e5%85%a8%e6%96%87%e6%a4%9c%e7%b4%a2%e3%82%a8%e3%83%b3%e3%82%b8%e3%83%b3%e3%82%92%e6%a7%8b%e7%af%89-5or%e6%bc%94%e7%ae%97-building-a-full-text-search-engine-on-java-5union-algorithm</guid>
		<description><![CDATA[前回がAND演算でしたので今回はOR演算ついて紹介します。今記事で紹介している演算アルゴリズムよりも高効率なものは存在するようですが、今回は割愛します。 OR演算処理の概要 上の図から、ある2つの語の転置インデックスリス &#8230; <a href="http://www.yukun.info/blog/2008/05/java-union.html">Continue reading <span class="meta-nav">&#8594;</span></a><p><a href="http://www.yukun.info/blog/2008/05/java-union.html">検索エンジンを実装 (5)OR演算</a> is a post from: <a href="http://www.yukun.info">Yukun&#039;s Blog</a></p>
]]></description>
			<content:encoded><![CDATA[<p>前回が<a href="http://www.yukun.info/blog/2008/05/java-intersection.html" title="検索エンジンを実装 (4)AND演算 | Trump Code">AND演算</a>でしたので今回はOR演算ついて紹介します。今記事で紹介している演算アルゴリズムよりも高効率なものは存在するようですが、今回は割愛します。</p>
<h3>OR演算処理の概要</h3>
<p><a href="http://www.yukun.info/wp-content/uploads/union.gif"><img src="http://www.yukun.info/wp-content/uploads/union-e1269626394691.gif" alt="OR演算結果" title="union" width="400" height="106" class="size-full wp-image-1477" /></a></p>
<p>上の図から、ある2つの語の転置インデックスリストをA, Bとします。ここで、リスト要素をそれぞれa, b(整数)とし演算結果を格納するリストをCとするとき、OR演算は主に以下の処理内容を繰り返します。</p>
<ol>
<li>if a < b then 要素aをCの末尾に追加し、aにリストAの次の要素を代入</li>
<li>if a = b then 要素aをCの末尾に追加し、A, Bが指す次の要素をa, bに代入</li>
<li>if a > b then 要素bをCの末尾に追加し、bにリストBの次の要素を代入</li>
</ol>
<h3>ソースコード</h3>
<p>今回はOR演算処理を行う部分(メソッド)のみを示します。後で示す実行結果は、<a href="http://www.yukun.info/blog/2008/05/java-intersection.html" title="検索エンジンを実装 (4)AND演算">前回</a>ブログラムをベースにintersect(postsSet)の箇所を今回のものに置き換えたものです。</p>
<pre>
import java.util.ArrayList;
import java.util.Collections;
/**
 * 検索エンジンのOR演算
 */
public class BooleanRetrieval {
  /**
   * OR演算処理
   * @param postsSet 全ての検索語の転置インデックスリスト
   * @return 演算後の転置インデックスリスト
   */
  public static ArrayList&lt;integer&gt; union(ArrayList&lt;arrayList&lt;integer&gt;&gt; postsSet) {
    ArrayList&lt;integer&gt; result; // 最終演算結果
    if (postsSet == null) return null;
    int len = postsSet.size();
    if (len == 0) return null;
    else if (len == 1) return postsSet.get(0);
    result = postsSet.get(0);
    for (int i = 1; i &lt; len; i++) {
      result = union(result, postsSet.get(i));
    }
    return result;
  }

  public static ArrayList&lt;integer&gt; union(ArrayList&lt;integer&gt; p1, ArrayList&lt;integer&gt; p2) {
    ArrayList&lt;integer&gt; answer = new ArrayList&lt;integer&gt;(); // 2語の演算結果
    int len1 = p1.size();
    int len2 = p2.size();
    int i=0, j=0;
    while (i&lt;len1 &amp;&amp; j&lt;len2) {
      int diff = p1.get(i) - p2.get(j);
      if (diff == 0) {
        answer.add(p1.get(i));
        i++; j++;
      } else if (diff &lt; 0) {
        answer.add(p1.get(i));
        i++;
      } else {
        answer.add(p2.get(j));
        j++;
      }
    }
    while (i&lt;len1) { answer.add(p1.get(i++)); }
    while (j&lt;len2) { answer.add(p2.get(j++)); }
    return answer;
  }
}
</pre>
<h3>OR演算の実行結果</h3>
<pre>単語          freq, docID
15           : 1, [2]
5            : 1, [2]
After        : 1, [1]
As           : 1, [1]
I            : 3, [0, 1, 2]
＜中略＞
should       : 2, [0, 1]
so           : 2, [1, 2]
some         : 1, [2]
standard     : 1, [0]
such         : 2, [1, 2]
than         : 1, [2]
that         : 1, [2]
the          : 3, [0, 1, 2]
think        : 3, [0, 1, 2]
this         : 1, [2]
time         : 2, [0, 2]
to           : 2, [0, 1]
touch        : 1, [1]
tremendously : 1, [1]
uncertainty  : 1, [1]
use          : 1, [2]
vigorous     : 1, [1]
wanna        : 1, [1]
well         : 1, [1]
what         : 1, [0]
when         : 1, [1]
where        : 1, [0]
why          : 1, [1]
with         : 1, [1]
検索語: the when
結果　:文書ID [0, 1, 2]に存在します。
検索語: should so
結果　:文書ID [0, 1, 2]に存在します。
検索語: this touch
結果　:文書ID [1, 2]に存在します。
検索語: use than
結果　:文書ID [2]に存在します。
検索語: where why
結果　:文書ID [0, 1]に存在します。
検索語: quit</pre>
<p>おー、なんだかもりあがってきましたねー。</p>
<p>話は変わりますが、最近よく実感していることの一つに、ソフトウェアの仕様が変更されると場合によっては設計を根本から変える必要があること。</p>
<p>そして、手がけているソフトウェアが今後アップグレードを繰り返していくと予測できるなら、現時点で取り組んでいる設計に費やす時間はほどほどに、ということです。OO分析設計を用いて保守性・拡張性を高めるのもいいけれど、その設計上での拡張が今後の仕様変更に耐えうるとは限りません。</p>
<p>勿論、最初の設計が肝心であることには変わりないですけれど。それでも留意。</p>
<h4>関連すると思われる記事：</h4>
<ul class="similar-posts">
<li><a href="http://www.yukun.info/blog/2008/06/java-subtraction.html" rel="bookmark" title="2008年6月4日">検索エンジンを実装 (6)NOT演算</a></li>
<li><a href="http://www.yukun.info/blog/2008/05/java-intersection.html" rel="bookmark" title="2008年5月20日">検索エンジンを実装 (4)AND演算</a></li>
<li><a href="http://www.yukun.info/blog/2008/03/java-ngram.html" rel="bookmark" title="2008年3月7日">検索エンジンを実装 (1)転置インデックス作成</a></li>
<li><a href="http://www.yukun.info/blog/2008/03/java-ngram-2.html" rel="bookmark" title="2008年3月16日">検索エンジンを実装 (2)出現位置とその文書ID</a></li>
<li><a href="http://www.yukun.info/blog/2008/03/java-ngram-3.html" rel="bookmark" title="2008年3月23日">検索エンジンを実装 (3)文書内の検索語を特定</a></li>
</ul>
<p><!-- Similar Posts took 14.263 ms --></p>
<p><a href="http://www.yukun.info/blog/2008/05/java-union.html">検索エンジンを実装 (5)OR演算</a> is a post from: <a href="http://www.yukun.info">Yukun&#039;s Blog</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.yukun.info/blog/2008/05/java-union.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>検索エンジンを実装 (4)AND演算</title>
		<link>http://www.yukun.info/blog/2008/05/java-intersection.html</link>
		<comments>http://www.yukun.info/blog/2008/05/java-intersection.html#comments</comments>
		<pubDate>Mon, 19 May 2008 15:00:00 +0000</pubDate>
		<dc:creator>yukun</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Search Engine]]></category>
		<category><![CDATA[Set]]></category>
		<category><![CDATA[String]]></category>
		<category><![CDATA[Strip]]></category>

		<guid isPermaLink="false">http://www.yukun.info/trump/19700101/java%e3%81%a7%e5%85%a8%e6%96%87%e6%a4%9c%e7%b4%a2%e3%82%a8%e3%83%b3%e3%82%b8%e3%83%b3%e3%82%92%e6%a7%8b%e7%af%89-4and%e6%bc%94%e7%ae%97-building-a-full-text-search-engine-on-java-4intersection-a</guid>
		<description><![CDATA[AND演算処理の概要 上の図から、ある2つの語の転置インデックスリストをA, Bとします。ここで、要素をそれぞれa, b(整数)とし演算結果を格納するリストをCとするとき、AND演算は主に以下の処理内容を繰り返します。  &#8230; <a href="http://www.yukun.info/blog/2008/05/java-intersection.html">Continue reading <span class="meta-nav">&#8594;</span></a><p><a href="http://www.yukun.info/blog/2008/05/java-intersection.html">検索エンジンを実装 (4)AND演算</a> is a post from: <a href="http://www.yukun.info">Yukun&#039;s Blog</a></p>
]]></description>
			<content:encoded><![CDATA[<h3>AND演算処理の概要</h3>
<p><a href="http://www.yukun.info/wp-content/uploads/intersection.gif"><img src="http://www.yukun.info/wp-content/uploads/intersection-e1269626508439.gif" alt="AND演算結果" title="intersection" width="400" height="128" class="size-full wp-image-1478" /></a></p>
<p>上の図から、ある2つの語の転置インデックスリストをA, Bとします。ここで、要素をそれぞれa, b(整数)とし演算結果を格納するリストをCとするとき、AND演算は主に以下の処理内容を繰り返します。</p>
<ol>
<li>if a < b then aの次の要素をaに代入</li>
<li>if a = b then 要素aをCの末尾に追加しA, Bが指す要素を一つ進める</li>
</ol>
<h3>プログラムの主な処理内容</h3>
<ol>
<li>検索対象テキストを単語に分割。</li>
<li>単語を転置インデックスに登録。ここで、1単語あたりに格納する情報は、その単語の出現頻度とその文書ID。転置インデックスのデータ構造はTreeMapを使用しkeyに単語、valueはIndexRecordでputします。</li>
<li>ユーザからの標準入力をパースしAND演算(Intersectメソッドで実現しています)。</li>
</ol>
<p>以下に、ソースコードと実行結果を示します。</p>
<h3>IndexRecord.java</h3>
<p>1つのトークン(単語)に対するインデックス情報（docIDリストや出現頻度情報）</p>
<pre>
import java.util.ArrayList;

/*
 * 1つのトークン(単語)に対するインデックス情報
 */
public class IndexRecord {
  // 出現文書IDリスト(通常ソートの必要あり)
  private ArrayList&lt;integer&gt; posts;
  // 出現頻度(今回は同一doc内の頻度はカウントしない)
  private int freq;

  public IndexRecord(int id) {
    posts = new ArrayList&lt;integer&gt;();
    posts.add(id);
    freq = 1;
  }

  /** docIDをリストに追加(今回は同一docIDのtermはカウントしない) */
  public void addDocID(int id) {
    if (!existDocID(id)) {
      posts.add(id); // docIDの追加
      freq++; // 出現頻度のカウントアップ
    }
  }

  /** docIDが既にリスト中に存在するか否か */
  public boolean existDocID(int id) {
    return (posts.indexOf(id) != -1) ? true : false;
  }

  public String toString() {
    String str = freq + &quot;, &quot;+ posts;
    return str;
  }

  public ArrayList&lt;integer&gt; getPosts() {
    return posts;
  }
}
</pre>
<h3>BooleanTest.java (AND演算のテストプログラム)</h3>
<pre>
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.StringTokenizer;
import java.util.TreeMap;

/**
 * 検索エンジンのAND演算処理
 * Web page: http://www.yukun.info/
 * license GPL
 */
public class BooleanTest {
  // 検索対象テキスト
  static String doc0 = &quot;It is meaningless only to think my long further aims idly. &quot;+
  &quot;It is important to set my aims but at the same time I should confirm my present condition. &quot;+
  &quot;Unless I set the standard where I am in any level, I&#039;ll be puzzled about what I should do from now on. It&#039;s in my case.&quot;;
  static String doc1 = &quot;Today, I enjoyed playing with friends daytime. &quot;+
  &quot;After enjoying, I got back to my daily life with an vigorous power. &quot;+
  &quot;I should think so, but why did I feel touch of uncertainty and regret? &quot;+
  &quot;I wanna enjoy myself and another tremendously during the day when I&#039;ve played. &quot;+
  &quot;Well, As well as I commit play to quality, I&#039;ll choose such kinds of play.&quot;;
  static String doc2 = &quot;I&#039;ll manage the limited time in a day. &quot;+
  &quot;I think that I divide the time into some intervals such as 5 minutes, &quot;+
  &quot;15 minutes and more than one hour and so on. I&#039;ll make use of this character of the interval.&quot;;

  public static void main(String[] args) {
    ArrayList&lt;string&gt; docIDlist = new ArrayList&lt;string&gt;();
    // 文書を格納
    docIDlist.add(doc0);
    docIDlist.add(doc1);
    docIDlist.add(doc2);
    StringTokenizer st[] = new StringTokenizer[3];
    String stripChars = &quot;.,:;?!&quot;&#039;[]{}()&quot;; // 除外文字

    // 文字列を空白で区切るよう設定
    for (int i = 0; i &lt; st.length; i++) {
      st[i] = new StringTokenizer(docIDlist.get(i), &quot; &quot;);
    }
    // 転置インデックス用のMap
    TreeMap&lt;string, IndexRecord&gt; termMap = new TreeMap&lt;string , IndexRecord&gt;();
    // 分割されたトークンを取得
    for (int i = 0; i &lt; st.length; i++) {
      // ここでのパラメータiはdocIDを指すことと同じ
      while (st[i].hasMoreTokens()) {
        // 文字列トークンの先頭・末尾の文字をフィルタリング
        // org.apache.commons.lang.StringUtilsクラスを使用
        // http://commons.apache.org/lang/
        String term = StringUtils.strip(st[i].nextToken(), stripChars);
        //System.out.println(&quot;値 : &quot; + term);
        if(termMap.containsKey(term)) {
          // 登録されているtermならdocIDの追加とカウントアップ
          IndexRecord ir = termMap.get(term);
          ir.addDocID(i);
          termMap.put(term, ir);
        } else {
          // termMapに登録されていないtermならdocIDと合わせて登録
          termMap.put(term, new IndexRecord(i));
        }

      }
    } // for loop ends

    // termMapのデバッグプリント
    System.out.println(&quot;単語          freq, docID&quot;);
    for (String part : termMap.keySet()) {
      System.out.printf(&quot;%-12s : %sn&quot;, part, termMap.get(part));
    }

    BufferedReader br =  new BufferedReader(new InputStreamReader(System.in));
    String words = &quot;&quot;;
    while (true) {
      ArrayList&lt;arrayList&lt;integer&gt;&gt; postsSet = new ArrayList&lt;arrayList&lt;integer&gt;&gt;();
      System.out.print(&quot;検索語: &quot;);
      try {
        // ユーザからの標準入力を受付
        words = br.readLine();
        if (words.equals(&quot;quit&quot;)) break;
        // 入力文字列をパース
        StringTokenizer parser = new StringTokenizer(words, &quot; &quot;);
        while (parser.hasMoreTokens()) {
          String term = StringUtils.strip(parser.nextToken(), stripChars);
          // termMapに登録されている単語か否か
          if (termMap.containsKey(term)) {
            postsSet.add(termMap.get(term).getPosts());
          } else {
            postsSet = null;
            break;
          }
        }

        // AND演算処理
        ArrayList&lt;integer&gt; result = intersect(postsSet);
        System.out.print(&quot;結果　:&quot;);
        if (result == null || result.size() == 0)
          System.out.println(&quot;文書中に存在しません。&quot;);
        else
          System.out.println(&quot;文書ID &quot;+ result +&quot;に存在します。&quot;);
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  } // main() ends

  // AND演算処理メソッド
  public static ArrayList&lt;integer&gt; intersect(ArrayList&lt;arrayList&lt;integer&gt;&gt; postsSet) {
    if (postsSet == null) return null;
    int len = postsSet.size();
    if (len == 0) return null;
    else if (len == 1) return postsSet.get(0);
    // postsSetを昇順にソート(演算回数の削減)
    Collections.sort(postsSet, new FreqComparator());
    ArrayList&lt; Integer &gt; result = postsSet.get(0);
    for (int i = 1; i &lt; len; i++) {
      result = intersect(result, postsSet.get(i));
    }
    return result;
  }

  public static ArrayList&lt;integer&gt; intersect(ArrayList&lt;integer&gt; p1, ArrayList&lt;integer&gt; p2) {
    ArrayList&lt;integer&gt; answer = new ArrayList&lt;integer&gt;();
    int len1 = p1.size();
    int len2 = p2.size();
    for (int i=0, j=0; i&lt; len1 &amp;&amp; j &lt; len2; ) {
      if (p1.get(i) == p2.get(j)) {
        answer.add(p1.get(i));
        i++; j++;
      } else if (p1.get(i) &lt; p2.get(j)) {
        i++;
      } else {
        j++;
      }
    }
    return answer;
  }
}
</pre>
<h3>FreqComparator.java (ArrayList要素のソート用)</h3>
<pre>

import java.util.ArrayList;
import java.util.Comparator;

public class FreqComparator implements Comparator&lt;object&gt;{
  public int compare(Object o1, Object o2){
    return ((ArrayList&lt;integer&gt;) o1).size() - ((ArrayList&lt;integer&gt;) o2).size();
  }
}
</pre>
<h3>実行結果</h3>
<pre>単語          freq, docID
15           : 1, [2]
5            : 1, [2]
After        : 1, [1]
As           : 1, [1]
I            : 3, [0, 1, 2]

＜中略＞

set          : 1, [0]
should       : 2, [0, 1]
so           : 2, [1, 2]
some         : 1, [2]
standard     : 1, [0]
such         : 2, [1, 2]
than         : 1, [2]
that         : 1, [2]
the          : 3, [0, 1, 2]
think        : 3, [0, 1, 2]
this         : 1, [2]
time         : 2, [0, 2]
to           : 2, [0, 1]
touch        : 1, [1]

＜中略＞

検索語: think that
結果　:文書ID [2]に存在します。
検索語: wanna play to
結果　:文書ID [1]に存在します。
検索語: the java
結果　:文書中に存在しません。
検索語: should so
結果　:文書ID [1]に存在します。
検索語: time to
結果　:文書ID [0]に存在します。
検索語: well only
結果　:文書中に存在しません。
検索語: the time
結果　:文書ID [0, 2]に存在します。
検索語: quit</pre>
<p>おー、なんだか楽しくなってきましたね。</p>
<h3>文字列の区切り方</h3>
<p>今回は検索対象テキストを英文に絞ったため、テキスト中の空白文字で区切ることでトークンを抽出できました。対して、日本語テキストの場合は区切り記号等は無い為、n-gramか形態素辞書などを用いてトークンに区切ることで実現できます。日本語文の区切り方は色々ありますが、中でも簡単な方法は、文字種（英文字、記号、ひらがな、カタカナ、漢字）の違いを区切りの境界と捉える方法です。</p>
<p>余談ですが、ブラウザやエディタ等で文字の上でダブルクリックするとカーソル下の文字列が選択状態になりますが、その範囲を決定する際に上述の方法が応用されているようです。ソフトによってはトリプルクリックするとカーソル下の行全体が選択状態になります（使うと編集が楽です）。</p>
<h4>関連すると思われる記事：</h4>
<ul class="similar-posts">
<li><a href="http://www.yukun.info/blog/2008/05/java-union.html" rel="bookmark" title="2008年5月27日">検索エンジンを実装 (5)OR演算</a></li>
<li><a href="http://www.yukun.info/blog/2008/06/java-subtraction.html" rel="bookmark" title="2008年6月4日">検索エンジンを実装 (6)NOT演算</a></li>
<li><a href="http://www.yukun.info/blog/2008/03/java-ngram.html" rel="bookmark" title="2008年3月7日">検索エンジンを実装 (1)転置インデックス作成</a></li>
<li><a href="http://www.yukun.info/blog/2008/03/java-ngram-2.html" rel="bookmark" title="2008年3月16日">検索エンジンを実装 (2)出現位置とその文書ID</a></li>
<li><a href="http://www.yukun.info/blog/2008/03/java-ngram-3.html" rel="bookmark" title="2008年3月23日">検索エンジンを実装 (3)文書内の検索語を特定</a></li>
</ul>
<p><!-- Similar Posts took 12.737 ms --></p>
<p><a href="http://www.yukun.info/blog/2008/05/java-intersection.html">検索エンジンを実装 (4)AND演算</a> is a post from: <a href="http://www.yukun.info">Yukun&#039;s Blog</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.yukun.info/blog/2008/05/java-intersection.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

