0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Elasticsearch&Python】AND検索とOR検索を組み合わせた複雑な検索クエリの書き方

Posted at

ElasticsearchでAND検索かつ、一部をOR検索にする。という複雑な検索クエリを書いたがちょっと書きにくかったので備忘録。

データ例

名前 カナ メールアドレス 部署 役職
佐藤一郎 サトウイチロウ i.sato@xxx.com 総務部 部長
田中二郎 タナカジロウ j.tanaka@xxx.com 総務部 室長
中村三郎 ナカムラサブロウ s.nakamura@xxx.com 営業部 部長
鈴木雄太 スズキユウタ y.suzuki@xxx.com 経理部 -
佐藤花子 サトウハナコ h.sato@xxx.com 経理部 -
山田太郎 ヤマダタロウ t.yamada@xxx.com 管理本部 本部長

条件詳細

例:名前が佐藤かつ、部署が総務部または経理部のユーザーを検索

上記のようにユーザー検索にて、名前、カナ、メールアドレス、部署、役職のAND検索に加え、部署と役職については複数項目でのOR検索をする。
また、名前は漢字、カナの両方で検索が入るようにしたい。ワタナベさんとかサイトウさんとか、漢字が複数ある方もいらっしゃいますからね、世の中。

クエリ

mustがAND検索、shouldがOR検索
shouldの場合はminimum_should_matchを設定する(最低n件一致しているか)

クエリの例(部署と役職は例として2件で検索する想定)

{
    "query": {
        "bool": {
            "must": [
                {
                    "bool": {
                        "should": [
                            "wildcard": {
                                "name.keyword": {"value": "*検索ワード*"}
                            },
                            "wildcard": {
                                "kana.keyword": {"value": "*検索ワード*"}
                            }
                        ]
                    }
                },
                {
                    "wildcard": {
                        "mail.keyword": {"value": "*検索ワード*"}
                    }
                },
                {
                    "bool": {
                        "should": [
                            "wildcard": {
                                "department.keyword": {"value": "*検索ワード*"}
                            },
                            "wildcard": {
                                "department.keyword": {"value": "*検索ワード*"}
                            }
                        ],
                        "minimum_should_match": 1
                    }
                },
                {
                    "bool": {
                        "should": [
                            "wildcard": {
                                "title.keyword": {"value": "*検索ワード*"}
                            },
                            "wildcard": {
                                "title.keyword": {"value": "*検索ワード*"}
                            }
                        ],
                        "minimum_should_match": 1
                    }
                },
            ]
        }
    }
}

pythonで関数にする

上記クエリをpythonで関数化すると以下のようになる。

# userインデックスのmanager.pyを想定

def search_user(self, name: str='', mail: str='', dep_list: List[str] = [], title_list: List[str] = []) -> list:
    # 空のクエリを作成
    query = {"query": {"bool": {}}}
    add_query = []

    # mustに入る中身を作成していく
    if name:
        add_query.append({
                    "bool": {
                        "should": [
                            "wildcard": {
                                "name.keyword": {"value": f"*{name}*"}
                            },
                            "wildcard": {
                                "kana.keyword": {"value": f"*{name}*"}
                            }
                        ]
                    }
                })
    if mail:
        add_query.append({
                    "wildcard": {
                        "mail.keyword": {"value": f"*{mail}*"}
                    }
                })
    if dep_list:
        dep_query = {"bool": {"should": {}}}
        dep_should = []
        for dep in dep_list:
            dep_should.append({"wildcard": {
                                "department.keyword": {"value": f"*{dep}*"}}})
        dep_query["bool"]["should"] = dep_should
        dep_query["bool"]["minimum_should_match"] = 1
    if title_list:
        title_query = {"bool": {"should": {}}}
        title_should = []
        for title in title_list:
            title_should.append({"wildcard": {
                                "title.keyword": {"value": f"*{title}*"}}})
        title_query["bool"]["should"] = title_should
        title_query["bool"]["minimum_should_match"] = 1

    # elasticsearchに接続して検索
    return self.es.search('user', query)

おわり

wildcardが便利、でも処理遅くなるからあんまり使わない方がいいらしいです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?