Django筆記四十一之Django中使用es

来源:https://www.cnblogs.com/hunterxiong/archive/2023/11/19/17841558.html
-Advertisement-
Play Games

本文首發於公眾號:Hunter後端 原文鏈接:Django筆記四十一之Django中使用es 前面在 Python 連接 es 的操作中,有過介紹如何使用 Python 代碼連接 es 以及對 es 數據進行增刪改查。 這一篇筆記介紹一下如何為 es 的 索引 index 定義一個 model,像 ...


本文首發於公眾號:Hunter後端

原文鏈接:Django筆記四十一之Django中使用es

前面在 Python 連接 es 的操作中,有過介紹如何使用 Python 代碼連接 es 以及對 es 數據進行增刪改查。

這一篇筆記介紹一下如何為 es 的 索引 index 定義一個 model,像 Django 里的 model 一樣使用 es。

因為本篇筆記要介紹的內容是直接嵌入在 Django 系統使用,所以本篇筆記直接歸屬於 Django 筆記系列。

本篇筆記目錄如下:

  1. es_model 示例及配置介紹
  2. 數據的增刪改查
  3. 欄位列表操作
  4. 嵌套類型操作
  5. 類函數
  6. 排序、取欄位等操作

1、es_model 示例及配置介紹

es 連接配置

首先我們要定義一下 es 的連接配置,這個在之前 Python 連接 es 的操作中有過介紹。

因為我們的 es 放在 Django 系統里,所以在系統啟動的時候就要載入,因此我們一般將其配置在 settings.py 中,示例如下:

# hunter/settings.py

from elasticsearch_dsl import connections

connections.configure(
    default={"hosts": "localhost:9200"},
)

模型示例

我們在 blog application 下建立一個 es_models.py 文件用於存儲我們的 es 索引模型:

# blog/es_models.py

from elasticsearch_dsl import Document, InnerDoc, Keyword, Text, Date, Integer, Float, Boolean

class BlogEs(Document):
    name = Keyword()
    tag_line = Text(fields={"keyword": Keyword()}, analyzer="ik_max_word")
    char_count = Integer()
    is_published = Boolean()
    pub_datetime = Date()
    blog_id = Integer()
    id = Integer()

    class Index:
        name = "blog"
        using = "private"

文件頂部引入的 Keyword,Text,Integer 等都是我們之前在介紹 es 的時候在 Python 里對應的數據類型。

Document

我們在建立每一個索引模型的時候都要繼承 Document,然後再定義相應的欄位。

在 BlogEs 中,我們這裡將大部分常用的欄位都定義上了,包括 Keyword,Text,Integer, Date等。

其中,對於 tag_line 欄位,這裡將其定義為 Text,那麼所存儲的文本內容會被分詞之後存儲,而我們同時定義它的子類型為 Keyword,則說明同時會將其文本作為一個整體存儲,欄位可以通過 tag_line__keyword 的方式搜索。

分詞模式

我們還為 tag_line 增加了一個 analyzer 參數,它的值是我們前面在 es 筆記中安裝的中文分詞插件的一種分詞模式,表示的是可以對存儲的文本進行重覆分詞。

這裡對中文分詞模式做一下簡單的介紹,我們安裝的分詞插件有兩種模式,一種 ik_smart,一種是 ik_max_word:

ik_smart

這種模式的分詞是將文本只拆分一次,假設要分詞的文本是 "一個蘋果",那麼分詞的結果就是,"一個" 和 "蘋果"。

ik_max_word

ik_max_word 的作用是將文本按照語義進行可能的重覆分詞,比如文本是 "一個蘋果",那麼分詞的結果就是 "一個","一","個","蘋果"。

Index

我們在每個 es 模型下都要定義一個 Index,其中的屬性這裡介紹兩個,一個是 name,一個是 using。

name 表示的是索引名稱

using 表示的是使用的 es 鏈接,es 的鏈接定義我們前面在 settings.py 里有定義,可以指定 using 的名稱,這裡不對 using 賦值的話預設取值為 default

keyword 和 text

什麼時候用到 Keyword,什麼時候用 Text 呢,這裡再贅述一下

選取哪種類型主要取決於我們欄位的業務屬性

一些需要用於整體搜索的欄位可以使用 Keyword 類型,姓名,郵箱、標簽等

大段文字的、不會被整體搜索的、需要搜索某些關鍵詞的欄位可以用 Text 欄位,比如博客標題,正文內容等

模型初始化

在首次使用每個 es 模型前,我們都需要對模型進行初始化的操作,其含義就是將索引各欄位對應的 mapping 寫入 es 中,這裡我們通過 python3 manage.py shell 來完成這個操作:

from blog.es_models import BlogEs
BlogEs.init()

初始化之後,我們可以在 kibana 里看到對應的 es 索引。

接下來我們嘗試對模型的數據進行增刪改查等操作。

2、數據的增刪改查

1.創建數據

單條創建數據

創建數據的方式很簡單,我們引入該 BlogEs,對其實例化後,對欄位進行挨個賦值,然後進行 save() 操作即可完成對一條數據的創建。

示例如下:

from blog.es_models import BlogEs

blog_es = BlogEs(
    name="如何學好Django",
    tag_line="這是一條tag_line",
)

blog_es.char_count = 98
blog_es.is_published = True
blog_es.pub_datetime = "2023-02-11 12:56:46"
blog_es.blog_id = 25
blog_es.meta.id = 25
blog_es.id = 78

blog_es.save()

這裡我們指定了 meta.id,指定的是這條數據的 _id 欄位,後面我們通過 get() 方法獲取數據的時候,所使用到的就是這個欄位。

如果不指定 meta.id,那麼 es 會自動為我們給該欄位賦值,上面我們創建了數據之後,在 kibana 中查詢結果如下:

      {
        "_index" : "blog",
        "_type" : "_doc",
        "_id" : "25",
        "_score" : 1.0,
        "_source" : {
          "name" : "如何學好Django",
          "tag_line" : "這是一條tag_line",
          "char_count" : 98,
          "is_published" : true,
          "pub_datetime" : "2023-02-11T12:56:46",
          "blog_id" : 25,
          "id" : 78
        }
      }

至此,我們單條數據即創建完畢。

批量創建數據

那麼如何批量創建數據呢,貌似這裡的官方文檔並沒有直接提供批量創建的方法,但是不要緊,我們可以使用 Python 連接 es 的筆記四的批量創建數據的方式。

2.查詢數據

查詢數據可以分為兩種,一種是按照 _id 參數進行查詢,比如 get() 和 mget(),一種是根據其他欄位進行查詢。

get()

我們可以使用 get() 方法獲取單條數據,這個就和 Django 的 model 的 get() 方式一樣。

但是 get() 方法只能使用 id 參數進行查詢,不接受其他欄位,比如我們 BlogEs 里定義的 name,char_count 這些欄位在這個方法里都不支持

而且,這裡的 id,指的是我們上面展示的這條數據的 _id 欄位,並非_source 裡面我們可以自定義的 id 欄位。

比如我們上面在 _source 里手動定義了 id 欄位的值為 78,我們去獲取數據 id=78:

BlogEs.get(id=78)

上面這條會報錯,而我們去獲取寫入的 id=25:

BlogEs.get(id=25)

則可以返回數據,因為這裡的 id 參數指定的是 meta.id

在這裡如果我們獲取不存在的 _id 欄位,則會報錯,為了防止這種情況,我們可以在 get() 方法裡加上 ignore=404 來忽略這種報錯,如果不存在對應條件的數據,則返回 None:

BlogEs.get(id=22, ignore=404)

因為不存在 _id=22 的數據,所以返回的數據就是 None

mget()

如果我們已知多條 _id 的值,我們通過 mget() 方法來一次性獲取多條數據,傳入的值是一個列表

id_list = [25, 78]
BlogEs.mget(id_list)

# [BlogEs(index='blog', id='25'), None]

如果在這個列表裡有不存在於 es 的數據,那麼對應返回的數據則是 None

query()

通過 es_model 使用 query 的方式和使用 Python 直接進行 es 的方式差不多,都是使用 query() 方法,示例如下:

from elasticsearch_dsl import Q as ES_Q
from blog.es_models import BlogEs

s = BlogEs.search()
query = s.query(ES_Q({"term": {"name": "如何學好Django"}}))
result = query.execute()
print(result)

# <Response: [BlogEs(index='blog', id='25')]>

或者使用 doc_type() 方法:

from elasticsearch_dsl import Search
s = Search()
s = s.doc_type(BlogEs)
query = s.query(ES_Q({"term": {"blog_id": 25}}))
result = query.execute()
print(result)

3.修改數據

我們修改的 es 數據來源可以是 get() 或者 query() 的方式

blog = BlogEs.get(id=25)
blog.name = "get修改"
blog.save()

s = BlogEs.search()
query = s.query(ES_Q({"term": {"blog_id": 25}}))
result = query.execute()
blog = result[0]
blog.name = "query修改"
blog.save()

使用 es_model 對數據進行修改有一個很方便的地方就是可以直接對數據進行 save 操作,相比 Python 連接 es 的方式而言。

4.刪除數據

對於單條數據,我們可以直接使用 delete() 方法:

blog = BlogEs.get(id=25)
blog.delete()

也可以使用 query().delete() 的方式:

s = BlogEs.search()
query = s.query(ES_Q({"term": {"blog_id": 25}}))
query.delete()

3、欄位列表操作

在 Python 里,常用欄位有 Keyword,Text,Date,Integer,Boolean,Float 等,和 es 中欄位相同,但是如果我們想存儲一個相同元素類型的列表欄位如何操作呢?

比如我們想存儲一個列表欄位,裡面的元素都是 Integer,假設 BlogEs 里存儲一個 id_list,裡面都是整數,應該如何定義和操作呢?

答案是直接操作。

因為 es 里並沒有列表這個類型的欄位,所以我們如果要為一個欄位賦值為列表,可以直接定義元素類型為目標類型,比如整型,字元串等,但是列表元素必須一致,然後操作的時候按照列表類型來操作即可。

以下是 BlogEs 的定義,省去了其他欄位:

class BlogEs(Document):
    id_list = Integer()

    class Index:
        name = "blog"

1.創建列表欄位

創建時定義 id_list:

blog_es = BlogEs()

blog_es.meta.id = 10
blog_es.id_list = [1, 2, 3]
blog_es.save()

2.修改列表欄位

修改 id_list,修改時可以直接重定義,也可以 append 添加,只要我們在定義欄位時用的列表,那麼在修改時可以直接對其進行列表操作:

blog_es = BlogEs.get(id=10)
blog_es.id_list = [1,4, 5]  # 直接重新定義
blog_es.id_list.append(8)  # 原數組添加元素
blog_es.id_list.append(9)
blog_es.save()

3.查詢列表欄位

查詢 id_list 中元素
現在我們創建兩條數據,之後的查詢都基於這兩條數據

blog_es = BlogEs()
blog_es.meta.id = 50
blog_es.id_list = [1, 2, 3]
blog_es.save()

blog_es_2 = BlogEs()
blog_es_2.meta.id = 50
blog_es_2.id_list = [1, 4, 5, 8, 9]
blog_es_2.save()

如果我們想查詢 id_list 中包含了 1 的數據,可以如下操作:

s = BlogEs.search()
condition = ES_Q({"term": {"id_list": 1}})
query = s.query(condition)
result = query.execute()

如果想查詢 id_list 中包含了 1 或者 8 的數據,任意包含其中一個元素即可,那麼可以如下操作:

s = BlogEs.search()
condition = ES_Q({"terms": {"id_list": [1, 8]}})
query = s.query(condition)
result = query.execute()

如果想查詢包含了 1 且 包含了 8 的數據,可以如下操作:

s = BlogEs.search()
condition = ES_Q({"term": {"id_list": 1}}) & ES_Q({"term": {"id_list": 8}})
query = s.query(condition)
result = query.execute()

4、嵌套類型操作

嵌套的類型是 Nested,前面我們介紹的數據存儲方式都是簡單的 key-value 的形式,嵌套的話,可以理解成是一個欄位作為 key,它的 value 則又是一個 key-value。

以下是一個示例:

# blog/es_models.py

from elasticsearch_dsl import Document, InnerDoc, Keyword, Text, Date, Boolean, Nested


class Comment(InnerDoc):
    author = Text()
    content = Text()


class Post(Document):
    title = Text()
    created_at = Date()
    published = Boolean()

    comments = Nested(Comment)

    class Index:
        name = "post"

在這裡,我們用 Nested() 作為嵌套欄位的類型,其中,我們通過定義 Comment 作為嵌套的對象

註意:嵌套的 Comment 繼承自 InnerDoc,且不需要進行 init() 操作。

1. 嵌套數據的創建

接下來我們創建幾條數據,嵌套的欄位 comments 為列表類型,保存多個 Comment 數據

先初始化 Post:

from blog.es_models import Post

Post.init()

創建兩條數據:

from blog.es_models import Post, Comment

comment_list = [
    Comment(author="張三", content="這是評論1"),
    Comment(author="李四", content="這是評論2"),
]

post = Post(
    title="post_title",
    published=1,
    comments=comment_list
)
post.save()


comment_list_2 = [
    Comment(author="張三", content="這是評論3"),
    Comment(author="王五", content="這是評論4"),
]


post_2 = Post(
    title="post_title_2",
    published=1,
    comments=comment_list_2
)
post_2.save()

2. 嵌套數據的查詢

嵌套數據的查詢也是使用 elasticsearch_dsl.Q,但是使用方式略有不同,他需要使用到 path 參數,然後指出我們查詢的欄位路徑

比如我們想查詢 comment 下 author 欄位值為 author_1 的數據,查詢示例如下:

from elasticsearch_dsl import Q as ES_Q

s = Post.search()
condition = ES_Q("nested", path="comments", query=ES_Q("term", comments__author="張三"))
query = s.query(condition)
result = query.execute()

3. 嵌套數據的修改和刪除

刪除和修改和之前的操作一樣,對於 comments 欄位的內容進行修改後 save() 操作即可

這裡我們演示示例如下:

# 獲取某個 meta.id 的數據
# 然後列印出 comments 欄位值
# 之後進行修改,保存操作
post = Post.get(id="yebzsYYSls5E4GzFd_WA")
print(post.comments)
post.comments = [Comment(author="孫悟空", content="孫悟空的評論")]
post.save()


# 獲取某個 meta.id 的數據
# 列印當前值
# 然後置空做刪除處理
post = Post.get(id="yebzsYYSls5E4GzFd_WA")
print(post.comments)
post.comments = []
post.save()

# 查看置空 comments 欄位後的數據情況
post = Post.get(id="yebzsYYSls5E4GzFd_WA")
print(post.comments)

5、類函數

每個 es_model 和 Django 里的 model 一樣,可以自定義函數來操作,比如我們想創建一條 Title 數據,參數直接傳入,可以如下操作

先定義我們的 model 然後重新進行 init() 操作:

from elasticsearch_dsl import Document, Text, Date, Boolean
from django.utils import timezone


class Title(Document):
    title = Text()
    created_at = Date()
    published = Boolean()

    class Index:
        name = "title"

    def create(self, title="", created_at=timezone.now(), published=True):
        self.title = title
        self.created_at = created_at
        self.published = published
        self.save()

創建數據:

from blog.es_models import Title

Title.init()

Title().create(title="this is a title")

6、排序、取欄位等操作

使用 es_model 對 es 進行排序、計數、指定欄位返回和直接使用 Python 的方式無異,下麵介紹一下示例。

1. 排序 sort()

如果我們想對 char_count 欄位進行排列操作,可以直接使用 sort()

這裡我們復用前面的 search() 操作:

s = BlogEs.search()
condition = ES_Q()
query = s.query(condition)

按照 char_count 倒序:

query = query.sort("-char_count")

按照 char_count 正序:

query = query.sort("char_count")

多欄位排序,按照 char_count 和 name 欄位排序:

query = query.sort("-char_count", "name")

2.指定欄位返回 source()

這裡我們指定 char_count 和 name 欄位返回:

query = query.source("char_count", "name")

3.extra()

排序和指定欄位返回我們也可以將參數傳入 extra(),然後進行操作,比如按照 char_count 欄位正序排列,name 欄位倒序,以及只返回 char_count 和 name 欄位

query = query.extra(
    sort=[
        {"char_count": {"order": "asc"}},
        {"name": {"order": "desc"}}
    ],
    _source=["char_count", "name"]
)

4.分頁操作

也可以在 extra() 中通過 from 和 size 實現分頁操作:

query = query.extra(
    **{
        "from": 2,
        "size": 3
    }
)

原文鏈接:[前面在 Python 連接 es 的操作中,有過介紹如何使用 Python 代碼連接 es 以及對 es 數據進行增刪改查。

這一篇筆記介紹一下如何為 es 的 索引 index 定義一個 model,像 Django 里的 model 一樣使用 es。

因為本篇筆記要介紹的內容是直接嵌入在 Django 系統使用,所以本篇筆記直接歸屬於 Django 筆記系列。

本篇筆記目錄如下:

  1. es_model 示例及配置介紹
  2. 數據的增刪改查
  3. 欄位列表操作
  4. 嵌套類型操作
  5. 類函數
  6. 排序、取欄位等操作

1、es_model 示例及配置介紹

es 連接配置

首先我們要定義一下 es 的連接配置,這個在之前 Python 連接 es 的操作中有過介紹。

因為我們的 es 放在 Django 系統里,所以在系統啟動的時候就要載入,因此我們一般將其配置在 settings.py 中,示例如下:

# hunter/settings.py

from elasticsearch_dsl import connections

connections.configure(
    default={"hosts": "localhost:9200"},
)

模型示例

我們在 blog application 下建立一個 es_models.py 文件用於存儲我們的 es 索引模型:

# blog/es_models.py

from elasticsearch_dsl import Document, InnerDoc, Keyword, Text, Date, Integer, Float, Boolean

class BlogEs(Document):
    name = Keyword()
    tag_line = Text(fields={"keyword": Keyword()}, analyzer="ik_max_word")
    char_count = Integer()
    is_published = Boolean()
    pub_datetime = Date()
    blog_id = Integer()
    id = Integer()

    class Index:
        name = "blog"
        using = "private"

文件頂部引入的 Keyword,Text,Integer 等都是我們之前在介紹 es 的時候在 Python 里對應的數據類型。

Document

我們在建立每一個索引模型的時候都要繼承 Document,然後再定義相應的欄位。

在 BlogEs 中,我們這裡將大部分常用的欄位都定義上了,包括 Keyword,Text,Integer, Date等。

其中,對於 tag_line 欄位,這裡將其定義為 Text,那麼所存儲的文本內容會被分詞之後存儲,而我們同時定義它的子類型為 Keyword,則說明同時會將其文本作為一個整體存儲,欄位可以通過 tag_line__keyword 的方式搜索。

分詞模式

我們還為 tag_line 增加了一個 analyzer 參數,它的值是我們前面在 es 筆記中安裝的中文分詞插件的一種分詞模式,表示的是可以對存儲的文本進行重覆分詞。

這裡對中文分詞模式做一下簡單的介紹,我們安裝的分詞插件有兩種模式,一種 ik_smart,一種是 ik_max_word:

ik_smart

這種模式的分詞是將文本只拆分一次,假設要分詞的文本是 "一個蘋果",那麼分詞的結果就是,"一個" 和 "蘋果"。

ik_max_word

ik_max_word 的作用是將文本按照語義進行可能的重覆分詞,比如文本是 "一個蘋果",那麼分詞的結果就是 "一個","一","個","蘋果"。

Index

我們在每個 es 模型下都要定義一個 Index,其中的屬性這裡介紹兩個,一個是 name,一個是 using。

name 表示的是索引名稱

using 表示的是使用的 es 鏈接,es 的鏈接定義我們前面在 settings.py 里有定義,可以指定 using 的名稱,這裡不對 using 賦值的話預設取值為 default

keyword 和 text

什麼時候用到 Keyword,什麼時候用 Text 呢,這裡再贅述一下

選取哪種類型主要取決於我們欄位的業務屬性

一些需要用於整體搜索的欄位可以使用 Keyword 類型,姓名,郵箱、標簽等

大段文字的、不會被整體搜索的、需要搜索某些關鍵詞的欄位可以用 Text 欄位,比如博客標題,正文內容等

模型初始化

在首次使用每個 es 模型前,我們都需要對模型進行初始化的操作,其含義就是將索引各欄位對應的 mapping 寫入 es 中,這裡我們通過 python3 manage.py shell 來完成這個操作:

from blog.es_models import BlogEs
BlogEs.init()

初始化之後,我們可以在 kibana 里看到對應的 es 索引。

接下來我們嘗試對模型的數據進行增刪改查等操作。

2、數據的增刪改查

1.創建數據

單條創建數據

創建數據的方式很簡單,我們引入該 BlogEs,對其實例化後,對欄位進行挨個賦值,然後進行 save() 操作即可完成對一條數據的創建。

示例如下:

from blog.es_models import BlogEs

blog_es = BlogEs(
    name="如何學好Django",
    tag_line="這是一條tag_line",
)

blog_es.char_count = 98
blog_es.is_published = True
blog_es.pub_datetime = "2023-02-11 12:56:46"
blog_es.blog_id = 25
blog_es.meta.id = 25
blog_es.id = 78

blog_es.save()

這裡我們指定了 meta.id,指定的是這條數據的 _id 欄位,後面我們通過 get() 方法獲取數據的時候,所使用到的就是這個欄位。

如果不指定 meta.id,那麼 es 會自動為我們給該欄位賦值,上面我們創建了數據之後,在 kibana 中查詢結果如下:

      {
        "_index" : "blog",
        "_type" : "_doc",
        "_id" : "25",
        "_score" : 1.0,
        "_source" : {
          "name" : "如何學好Django",
          "tag_line" : "這是一條tag_line",
          "char_count" : 98,
          "is_published" : true,
          "pub_datetime" : "2023-02-11T12:56:46",
          "blog_id" : 25,
          "id" : 78
        }
      }

至此,我們單條數據即創建完畢。

批量創建數據

那麼如何批量創建數據呢,貌似這裡的官方文檔並沒有直接提供批量創建的方法,但是不要緊,我們可以使用 Python 連接 es 的筆記四的批量創建數據的方式。

2.查詢數據

查詢數據可以分為兩種,一種是按照 _id 參數進行查詢,比如 get() 和 mget(),一種是根據其他欄位進行查詢。

get()

我們可以使用 get() 方法獲取單條數據,這個就和 Django 的 model 的 get() 方式一樣。

但是 get() 方法只能使用 id 參數進行查詢,不接受其他欄位,比如我們 BlogEs 里定義的 name,char_count 這些欄位在這個方法里都不支持

而且,這裡的 id,指的是我們上面展示的這條數據的 _id 欄位,並非_source 裡面我們可以自定義的 id 欄位。

比如我們上面在 _source 里手動定義了 id 欄位的值為 78,我們去獲取數據 id=78:

BlogEs.get(id=78)

上面這條會報錯,而我們去獲取寫入的 id=25:

BlogEs.get(id=25)

則可以返回數據,因為這裡的 id 參數指定的是 meta.id

在這裡如果我們獲取不存在的 _id 欄位,則會報錯,為了防止這種情況,我們可以在 get() 方法裡加上 ignore=404 來忽略這種報錯,如果不存在對應條件的數據,則返回 None:

BlogEs.get(id=22, ignore=404)

因為不存在 _id=22 的數據,所以返回的數據就是 None

mget()

如果我們已知多條 _id 的值,我們通過 mget() 方法來一次性獲取多條數據,傳入的值是一個列表

id_list = [25, 78]
BlogEs.mget(id_list)

# [BlogEs(index='blog', id='25'), None]

如果在這個列表裡有不存在於 es 的數據,那麼對應返回的數據則是 None

query()

通過 es_model 使用 query 的方式和使用 Python 直接進行 es 的方式差不多,都是使用 query() 方法,示例如下:

from elasticsearch_dsl import Q as ES_Q
from blog.es_models import BlogEs

s = BlogEs.search()
query = s.query(ES_Q({"term": {"name": "如何學好Django"}}))
result = query.execute()
print(result)

# <Response: [BlogEs(index='blog', id='25')]>

或者使用 doc_type() 方法:

from elasticsearch_dsl import Search
s = Search()
s = s.doc_type(BlogEs)
query = s.query(ES_Q({"term": {"blog_id": 25}}))
result = query.execute()
print(result)

3.修改數據

我們修改的 es 數據來源可以是 get() 或者 query() 的方式

blog = BlogEs.get(id=25)
blog.name = "get修改"
blog.save()

s = BlogEs.search()
query = s.query(ES_Q({"term": {"blog_id": 25}}))
result = query.execute()
blog = result[0]
blog.name = "query修改"
blog.save()

使用 es_model 對數據進行修改有一個很方便的地方就是可以直接對數據進行 save 操作,相比 Python 連接 es 的方式而言。

4.刪除數據

對於單條數據,我們可以直接使用 delete() 方法:

blog = BlogEs.get(id=25)
blog.delete()

也可以使用 query().delete() 的方式:

s = BlogEs.search()
query = s.query(ES_Q({"term": {"blog_id": 25}}))
query.delete()

3、欄位列表操作

在 Python 里,常用欄位有 Keyword,Text,Date,Integer,Boolean,Float 等,和 es 中欄位相同,但是如果我們想存儲一個相同元素類型的列表欄位如何操作呢?

比如我們想存儲一個列表欄位,裡面的元素都是 Integer,假設 BlogEs 里存儲一個 id_list,裡面都是整數,應該如何定義和操作呢?

答案是直接操作。

因為 es 里並沒有列表這個類型的欄位,所以我們如果要為一個欄位賦值為列表,可以直接定義元素類型為目標類型,比如整型,字元串等,但是列表元素必須一致,然後操作的時候按照列表類型來操作即可。

以下是 BlogEs 的定義,省去了其他欄位:

class BlogEs(Document):
    id_list = Integer()

    class Index:
        name = "blog"

1.創建列表欄位

創建時定義 id_list:

blog_es = BlogEs()

blog_es.meta.id = 10
blog_es.id_list = [1, 2, 3]
blog_es.save()

2.修改列表欄位

修改 id_list,修改時可以直接重定義,也可以 append 添加,只要我們在定義欄位時用的列表,那麼在修改時可以直接對其進行列表操作:

blog_es = BlogEs.get(id=10)
blog_es.id_list = [1,4, 5]  # 直接重新定義
blog_es.id_list.append(8)  # 原數組添加元素
blog_es.id_list.append(9)
blog_es.save()

3.查詢列表欄位

查詢 id_list 中元素
現在我們創建兩條數據,之後的查詢都基於這兩條數據

blog_es = BlogEs()
blog_es.meta.id = 50
blog_es.id_list = [1, 2, 3]
blog_es.save()

blog_es_2 = BlogEs()
blog_es_2.meta.id = 50
blog_es_2.id_list = [1, 4, 5, 8, 9]
blog_es_2.save()

如果我們想查詢 id_list 中包含了 1 的數據,可以如下操作:

s = BlogEs.search()
condition = ES_Q({"term": {"id_list": 1}})
query = s.query(condition)
result = query.execute()

如果想查詢 id_list 中包含了 1 或者 8 的數據,任意包含其中一個元素即可,那麼可以如下操作:

s = BlogEs.search()
condition = ES_Q({"terms": {"id_list": [1, 8]}})
query = s.query(condition)
result = query.execute()

如果想查詢包含了 1 且 包含了 8 的數據,可以如下操作:

s = BlogEs.search()
condition = ES_Q({"term": {"id_list": 1}}) & ES_Q({"term": {"id_list": 8}})
query = s.query(condition)
result = query.execute()

4、嵌套類型操作

嵌套的類型是 Nested,前面我們介紹的數據存儲方式都是簡單的 key-value 的形式,嵌套的話,可以理解成是一個欄位作為 key,它的 value 則又是一個 key-value。

以下是一個示例:

# blog/es_models.py

from elasticsearch_dsl import Document, InnerDoc, Keyword, Text, Date, Boolean, Nested


class Comment(InnerDoc):
    author = Text()
    content = Text()


class Post(Document):
    title = Text()
    created_at = Date()
    published = Boolean()

    comments = Nested(Comment)

    class Index:
        name = "post"

在這裡,我們用 Nested() 作為嵌套欄位的類型,其中,我們通過定義 Comment 作為嵌套的對象

註意:嵌套的 Comment 繼承自 InnerDoc,且不需要進行 init() 操作。

1. 嵌套數據的創建

接下來我們創建幾條數據,嵌套的欄位 comments 為列表類型,保存多個 Comment 數據

先初始化 Post:

from blog.es_models import Post

Post.init()

創建兩條數據:

from blog.es_models import Post, Comment

comment_list = [
    Comment(author="張三", content="這是評論1"),
    Comment(author="李四", content="這是評論2"),
]

post = Post(
    title="post_title",
    published=1,
    comments=comment_list
)
post.save()


comment_list_2 = [
    Comment(author="張三", content="這是評論3"),
    Comment(author="王五", content="這是評論4"),
]


post_2 = Post(
    title="post_title_2",
    published=1,
    comments=comment_list_2
)
post_2.save()

2. 嵌套數據的查詢

嵌套數據的查詢也是使用 elasticsearch_dsl.Q,但是使用方式略有不同,他需要使用到 path 參數,然後指出我們查詢的欄位路徑

比如我們想查詢 comment 下 author 欄位值為 author_1 的數據,查詢示例如下:

from elasticsearch_dsl import Q as ES_Q

s = Post.search()
condition = ES_Q("nested", path="comments", query=ES_Q("term", comments__author="張三"))
query = s.query(condition)
result = query.execute()

3. 嵌套數據的修改和刪除

刪除和修改和之前的操作一樣,對於 comments 欄位的內容進行修改後 save() 操作即可

這裡我們演示示例如下:

# 獲取某個 meta.id 的數據
# 然後列印出 comments 欄位值
# 之後進行修改,保存操作
post = Post.get(id="yebzsYYSls5E4GzFd_WA")
print(post.comments)
post.comments = [Comment(author="孫悟空", content="孫悟空的評論")]
post.save()


# 獲取某個 meta.id 的數據
# 列印當前值
# 然後置空做刪除處理
post = Post.get(id="yebzsYYSls5E4GzFd_WA")
print(post.comments)
post.comments = []
post.save()

# 查看置空 comments 欄位後的數據情況
post = Post.get(id="yebzsYYSls5E4GzFd_WA")
print(post.comments)

5、類函數

每個 es_model 和 Django 里的 model 一樣,可以自定義函數來操作,比如我們想創建一條 Title 數據,參數直接傳入,可以如下操作

先定義我們的 model 然後重新進行 init() 操作:

from elasticsearch_dsl import Document, Text, Date, Boolean
from django.utils import timezone


class Title(Document):
    title = Text()
    created_at = Date()
    published = Boolean()

    class Index:
        name = "title"

    def create(self, title="", created_at=timezone.now(), published=True):
        self.title = title
        self.created_at = created_at
        self.published = published
        self.save()

創建數據:

from blog.es_models import Title

Title.init()

Title().create(title="this is a title")

6、排序、取欄位等操作

使用 es_model 對 es 進行排序、計數、指定欄位返回和直接使用 Python 的方式無異,下麵介紹一下示例。

1. 排序 sort()

如果我們想對 char_count 欄位進行排列操作,可以直接使用 sort()

這裡我們復用前面的 search() 操作:

s = BlogEs.search()
condition = ES_Q()
query = s.query(condition)

按照 char_count 倒序:

query = query.sort("-char_count")

按照 char_count 正序:

query = query.sort("char_count")

多欄位排序,按照 char_count 和 name 欄位排序:

query = query.sort("-char_count", "name")

2.指定欄位返回 source()

這裡我們指定 char_count 和 name 欄位返回:

query = query.source("char_count", "name")

3.extra()

排序和指定欄位返回我們也可以將參數傳入 extra(),然後進行操作,比如按照 char_count 欄位正序排列,name 欄位倒序,以及只返回 char_count 和 name 欄位

query = query.extra(
    sort=[
        {"char_count": {"order": "asc"}},
        {"name": {"order": "desc"}}
    ],
    _source=["char_count", "name"]
)

4.分頁操作

也可以在 extra() 中通過 from 和 size 實現分頁操作:

query = query.extra(
    **{
        "from": 2,
        "size": 3
    }
)

如果想獲取更多相關文章,可掃碼關註閱讀:

image


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 什麼是主構造函數 把參數添加到class與record的類聲明中就是主構造函數。例如 class Person(string name) { private string _name = name; } 這種寫法與以下代碼寫法一樣 class Person { private string _nam ...
  • 背景 工作需要對接內部的日誌中台,對日誌列印有固定的格式要求,為了使Nginx的access日誌也能被採集,需要對日誌格式進行自定義,要求日誌格式為: yyyy-MM-dd HH:mm:ss.SSS LOG_LEVEL LOG_MSG > 時間格式+列印級別+業務日誌 如: 23-11-18 17: ...
  • 作為小白的我這幾天買了個香橙派3b 經過這幾天的折騰,終於進入了ssh終端(大喜 我買的是官店的8G,創客價299,連著一起買了一個閃迪的64gTF卡 簡單總結一下搭建過程: 物理準備:一臺電腦,香橙派與一張16G以上的tf卡,tf讀卡器(一般會送)一根網線,type-c線 第一步:燒錄ubuntu ...
  • CycloneIII內部資源概述 目錄CycloneIII內部資源概述Logic Elements and Logic Array Blocks(邏輯元件和邏輯陣列塊)LELABLAB InterconnectsMemory Blocks(記憶體塊)Memory modeClocking modeEm ...
  • DM8壓縮表 0、結論 行表(普通表)不支持壓縮。但是語法支持。建表之後,查詢到的占用空間會比普通表小一半。 經過測試,裝10萬數據(兩個欄位),壓縮的、未壓縮,占用空間一樣大。 列表(huge表)支持壓縮。可以壓縮表(就是壓縮所有列),也可以選擇壓縮列。但是建表的時候就要設置,否則建好表之後修改不 ...
  • 本文介紹MySQL和PostgreSQL的一些特性對比,讓大家瞭解二者的優劣,更好的做出選擇。當前國內的現狀,互聯網公司使用MySQL的較多,PostgreSQL的使用比例反而不高,但相信看到PG的新特性後,你會愛上她。當然MySQL作為最流行的資料庫,依然會吸引大部分人的眼球。 PostgreSQ ...
  • 原文:Android Material組件庫(日期選擇和時間選擇器)基本使用 - Stars-One的雜貨小窩 簡單的封裝下Material組件里的日期選擇器和時間選擇器的使用方法 效果 代碼 需要添加Material組件庫的依賴(不過後面新版本Android Studio創建的新項目都會有此依賴了 ...
  • 可以少去理解一些不必要的概念,而多去思考為什麼會有這樣的東西,它解決了什麼問題,或者它的運行機制是什麼? JS JavaScript 是互聯網上最流行的腳本語言,這門語言可用於 HTML 和 web,更可廣泛用於伺服器、PC、筆記本電腦、平板電腦和智能手機等設備。 https://www.runoo ...
一周排行
    -Advertisement-
    Play Games
  • 前言 微服務架構已經成為搭建高效、可擴展系統的關鍵技術之一,然而,現有許多微服務框架往往過於複雜,使得我們普通開發者難以快速上手並體驗到微服務帶了的便利。為瞭解決這一問題,於是作者精心打造了一款最接地氣的 .NET 微服務框架,幫助我們輕鬆構建和管理微服務應用。 本框架不僅支持 Consul 服務註 ...
  • 先看一下效果吧: 如果不會寫動畫或者懶得寫動畫,就直接交給Blend來做吧; 其實Blend操作起來很簡單,有點類似於在操作PS,我們只需要設置關鍵幀,滑鼠點來點去就可以了,Blend會自動幫我們生成我們想要的動畫效果. 第一步:要創建一個空的WPF項目 第二步:右鍵我們的項目,在最下方有一個,在B ...
  • Prism:框架介紹與安裝 什麼是Prism? Prism是一個用於在 WPF、Xamarin Form、Uno 平臺和 WinUI 中構建鬆散耦合、可維護和可測試的 XAML 應用程式框架 Github https://github.com/PrismLibrary/Prism NuGet htt ...
  • 在WPF中,屏幕上的所有內容,都是通過畫筆(Brush)畫上去的。如按鈕的背景色,邊框,文本框的前景和形狀填充。藉助畫筆,可以繪製頁面上的所有UI對象。不同畫筆具有不同類型的輸出( 如:某些畫筆使用純色繪製區域,其他畫筆使用漸變、圖案、圖像或繪圖)。 ...
  • 前言 嗨,大家好!推薦一個基於 .NET 8 的高併發微服務電商系統,涵蓋了商品、訂單、會員、服務、財務等50多種實用功能。 項目不僅使用了 .NET 8 的最新特性,還集成了AutoFac、DotLiquid、HangFire、Nlog、Jwt、LayUIAdmin、SqlSugar、MySQL、 ...
  • 本文主要介紹攝像頭(相機)如何採集數據,用於類似攝像頭本地顯示軟體,以及流媒體數據傳輸場景如傳屏、視訊會議等。 攝像頭採集有多種方案,如AForge.NET、WPFMediaKit、OpenCvSharp、EmguCv、DirectShow.NET、MediaCaptre(UWP),網上一些文章以及 ...
  • 前言 Seal-Report 是一款.NET 開源報表工具,擁有 1.4K Star。它提供了一個完整的框架,使用 C# 編寫,最新的版本採用的是 .NET 8.0 。 它能夠高效地從各種資料庫或 NoSQL 數據源生成日常報表,並支持執行複雜的報表任務。 其簡單易用的安裝過程和直觀的設計界面,我們 ...
  • 背景需求: 系統需要對接到XXX官方的API,但因此官方對接以及管理都十分嚴格。而本人部門的系統中包含諸多子系統,系統間為了穩定,程式間多數固定Token+特殊驗證進行調用,且後期還要提供給其他兄弟部門系統共同調用。 原則上:每套系統都必須單獨接入到官方,但官方的接入複雜,還要官方指定機構認證的證書 ...
  • 本文介紹下電腦設備關機的情況下如何通過網路喚醒設備,之前電源S狀態 電腦Power電源狀態- 唐宋元明清2188 - 博客園 (cnblogs.com) 有介紹過遠程喚醒設備,後面這倆天瞭解多了點所以單獨加個隨筆 設備關機的情況下,使用網路喚醒的前提條件: 1. 被喚醒設備需要支持這WakeOnL ...
  • 前言 大家好,推薦一個.NET 8.0 為核心,結合前端 Vue 框架,實現了前後端完全分離的設計理念。它不僅提供了強大的基礎功能支持,如許可權管理、代碼生成器等,還通過採用主流技術和最佳實踐,顯著降低了開發難度,加快了項目交付速度。 如果你需要一個高效的開發解決方案,本框架能幫助大家輕鬆應對挑戰,實 ...