Hive基於UDF進行文本分詞

2021-01-15 Java大數據與數據倉庫
本文大綱UDF 簡介

Hive作為一個sql查詢引擎,自帶了一些基本的函數,比如count(計數),sum(求和),有時候這些基本函數滿足不了我們的需求,這時候就要寫hive hdf(user defined funation),又叫用戶自定義函數。編寫Hive UDF的步驟:

添加相關依賴,創建項目,這裡我用的管理工具是maven,所以我創建的也是一個maven 項目(這個時候你需要選擇合適的依賴版本,主要是Hadoop 和 Hive,可以使用hadoop version和hive --version 來分別查看版本)

繼承org.apache.hadoop.hive.ql.exec.UDF類,實現evaluate方法,然後打包;

使用 add方法添加jar 包到分布式緩存,如果jar包是上傳到$HIVE_HOME/lib/目錄以下,就不需要執行add命令了

通過create temporary function創建臨時函數,不加temporary就創建了一個永久函數;

在SQL 中使用你創建的UDF;

UDF分詞

這個是一個比較常見的場景,例如公司的產品有每天都會產生大量的彈幕或者評論,這個時候我們可能會想去分析一下大家最關心的熱點話題是什麼,或者是我們會分析最近一段時間的網絡趨勢是什麼,但是這裡有一個問題就是你的詞庫建設的問題,因為你使用通用的詞庫可能不能達到很好的分詞效果,尤其有很多網絡流行用語它是不在詞庫裡的,還有一個就是停用詞的問題了,因為很多時候停用詞是沒有意義的,所以這裡我們需要將其過濾,而過濾的方式就是通過停用詞詞表進行過濾。

這個時候我們的解決方案主要有兩種,一種是使用第三方提供的一些詞庫,還有一種是自建詞庫,然後有專人去維護,這個也是比較常見的一種情況。

最後一個就是我們使用的分詞工具,因為目前主流的分詞器很多,選擇不同的分詞工具可能對我們的分詞結果有很多影響。

分詞工具

1:Elasticsearch的開源中文分詞器 IK Analysis(Star:2471)

IK中文分詞器在Elasticsearch上的使用。原生IK中文分詞是從文件系統中讀取詞典,es-ik本身可擴展成從不同的源讀取詞典。目前提供從sqlite3資料庫中讀取。es-ik-plugin-sqlite3使用方法:1. 在elasticsearch.yml中設置你的sqlite3詞典的位置:ik_analysis_db_path: /opt/ik/dictionary.db

2:開源的java中文分詞庫 IKAnalyzer(Star:343)

IK Analyzer 是一個開源的,基於java語言開發的輕量級的中文分詞工具包。從2006年12月推出1.0版開始, IKAnalyzer已經推出了4個大版本。最初,它是以開源項目Luence為應用主體的,結合詞典分詞和文法分析算法的中文分詞組件。從3.0版本開始,IK發展為面向Java的公用分詞組件,獨立於Lucene項目

3:java開源中文分詞 Ansj(Star:3019)

Ansj中文分詞 這是一個ictclas的java實現.基本上重寫了所有的數據結構和算法.詞典是用的開源版的ictclas所提供的.並且進行了部分的人工優化 分詞速度達到每秒鐘大約200萬字左右,準確率能達到96%以上。

目前實現了.中文分詞. 中文姓名識別 . 詞性標註、用戶自定義詞典,關鍵字提取,自動摘要,關鍵字標記等功能。

可以應用到自然語言處理等方面,適用於對分詞效果要求高的各種項目.

4:結巴分詞 ElasticSearch 插件(Star:188)

elasticsearch官方只提供smartcn這個中文分詞插件,效果不是很好,好在國內有medcl大神(國內最早研究es的人之一)寫的兩個中文分詞插件,一個是ik的,一個是mmseg的

5:Java分布式中文分詞組件 - word分詞(Star:672)

word分詞是一個Java實現的分布式的中文分詞組件,提供了多種基於詞典的分詞算法,並利用ngram模型來消除歧義。能準確識別英文、數字,以及日期、時間等數量詞,能識別人名、地名、組織機構名等未登錄詞

6:Java開源中文分詞器jcseg(Star:400)

Jcseg是什麼?Jcseg是基於mmseg算法的一個輕量級開源中文分詞器,同時集成了關鍵字提取,關鍵短語提取,關鍵句子提取和文章自動摘要等功能,並且提供了最新版本的lucene, solr, elasticsearch的分詞接口, Jcseg自帶了一個 jcseg.properties文件…

7:中文分詞庫Paoding

庖丁中文分詞庫是一個使用Java開發的,可結合到Lucene應用中的,為網際網路、企業內部網使用的中文搜尋引擎分詞組件。Paoding填補了國內中文分詞方面開源組件的空白,致力於此並希翼成為網際網路網站首選的中文分詞開源組件。Paoding中文分詞追求分詞的高效率和用戶良好體驗。

8:中文分詞器mmseg4j

mmseg4j 用 Chih-Hao Tsai 的 MMSeg 算法(http://technology.chtsai.org/mmseg/ )實現的中文分詞器,並實現 lucene 的 analyzer 和 solr 的TokenizerFactory 以方便在Lucene和Solr中使…

9:中文分詞Ansj(Star:3015)

Ansj中文分詞 這是一個ictclas的java實現.基本上重寫了所有的數據結構和算法.詞典是用的開源版的ictclas所提供的.並且進行了部分的人工優化 內存中中文分詞每秒鐘大約100萬字(速度上已經超越ictclas) 文件讀取分詞每秒鐘大約30萬字 準確率能達到96%以上 目前實現了….

10:Lucene中文分詞庫ICTCLAS4J

ictclas4j中文分詞系統是sinboy在中科院張華平和劉群老師的研製的FreeICTCLAS的基礎上完成的一個java開源分詞項目,簡化了原分詞程序的複雜度,旨在為廣大的中文分詞愛好者一個更好的學習機會。

代碼實現第一步:引入依賴

這裡我們引入了兩個依賴,其實是兩個不同分詞工具

<dependency>
  <groupId>org.ansj</groupId>
  <artifactId>ansj_seg</artifactId>
  <version>5.1.6</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>com.janeluo</groupId>
  <artifactId>ikanalyzer</artifactId>
  <version>2012_u6</version>
</dependency>

在開始之前我們先寫一個demo 玩玩,讓大家有個基本的認識

@Test
public  void testAnsjSeg() {
    String str = "我叫李太白,我是一個詩人,我生活在唐朝" ;
      // 選擇使用哪種分詞器 BaseAnalysis ToAnalysis NlpAnalysis  IndexAnalysis
    Result result = ToAnalysis.parse(str);
    System.out.println(result);
    KeyWordComputer kwc = new KeyWordComputer(5);
    Collection<Keyword> keywords = kwc.computeArticleTfidf(str);
    System.out.println(keywords);
}

輸出結果

我/r,叫/v,李太白/nr,,/w,我/r,是/v,一個/m,詩人/n,,/w,我/r,生活/vn,在/p,唐朝/t
[李太白/24.72276098504223, 詩人/3.0502185968368885, 唐朝/0.8965677022546215, 生活/0.6892230219652541]

第二步:引入停用詞詞庫

因為是停用詞詞庫,本身也不是很大,所以我直接放在項目裡了,當然你也可以放在其他地方,例如HDFS 上

第三步:編寫UDF

代碼很簡單我就不不做詳細解釋了,需要注意的是GenericUDF 裡面的一些方法的使用規則,至於代碼設計的好壞以及還有什麼改進的方案我們後面再說,下面兩套實現的思路幾乎是一致的,不一樣的是在使用的分詞工具上的不一樣

ansj的實現

/**
 * Chinese words segmentation with user-dict in com.kingcall.dic
 * use Ansj(a java open source analyzer)
 */

// 這個信息就是你每次使用desc 進行獲取函數信息的時候返回的
@Description(name = "ansj_seg", value = "_FUNC_(str) - chinese words segment using ansj. Return list of words.",
        extended = "Example: select _FUNC_('我是測試字符串') from src limit 1;\n"
                + "[\"我\", \"是\", \"測試\", \"字符串\"]")

public class AnsjSeg extends GenericUDF {
    private transient ObjectInspectorConverters.Converter[] converters;
    private static final String userDic = "/app/stopwords/com.kingcall.dic";

    //load userDic in hdfs
    static {
        try {
            FileSystem fs = FileSystem.get(new Configuration());
            FSDataInputStream in = fs.open(new Path(userDic));
            BufferedReader br = new BufferedReader(new InputStreamReader(in));

            String line = null;
            String[] strs = null;
            while ((line = br.readLine()) != null) {
                line = line.trim();
                if (line.length() > 0) {
                    strs = line.split("\t");
                    strs[0] = strs[0].toLowerCase();
                    DicLibrary.insert(DicLibrary.DEFAULT, strs[0]); //ignore nature and freq
                }
            }
            MyStaticValue.isNameRecognition = Boolean.FALSE;
            MyStaticValue.isQuantifierRecognition = Boolean.TRUE;
        } catch (Exception e) {
            System.out.println("Error when load userDic" + e.getMessage());
        }
    }

    @Override
    public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
        if (arguments.length < 1 || arguments.length > 2) {
            throw new UDFArgumentLengthException(
                    "The function AnsjSeg(str) takes 1 or 2 arguments.");
        }

        converters = new ObjectInspectorConverters.Converter[arguments.length];
        converters[0] = ObjectInspectorConverters.getConverter(arguments[0], PrimitiveObjectInspectorFactory.writableStringObjectInspector);
        if (2 == arguments.length) {
            converters[1] = ObjectInspectorConverters.getConverter(arguments[1], PrimitiveObjectInspectorFactory.writableIntObjectInspector);
        }
        return ObjectInspectorFactory.getStandardListObjectInspector(PrimitiveObjectInspectorFactory.writableStringObjectInspector);
    }


    @Override
    public Object evaluate(DeferredObject[] arguments) throws HiveException {
        boolean filterStop = false;
        if (arguments[0].get() == null) {
            return null;
        }
        if (2 == arguments.length) {
            IntWritable filterParam = (IntWritable) converters[1].convert(arguments[1].get());
            if (1 == filterParam.get()) filterStop = true;
        }

        Text s = (Text) converters[0].convert(arguments[0].get());
        ArrayList<Text> result = new ArrayList<>();

        if (filterStop) {
            for (Term words : DicAnalysis.parse(s.toString()).recognition(StopLibrary.get())) {
                if (words.getName().trim().length() > 0) {
                    result.add(new Text(words.getName().trim()));
                }
            }
        } else {
            for (Term words : DicAnalysis.parse(s.toString())) {
                if (words.getName().trim().length() > 0) {
                    result.add(new Text(words.getName().trim()));
                }
            }
        }
        return result;
    }


    @Override
    public String getDisplayString(String[] children) {
        return getStandardDisplayString("ansj_seg", children);
    }
}

ikanalyzer的實現

@Description(name = "ansj_seg", value = "_FUNC_(str) - chinese words segment using Iknalyzer. Return list of words.",
        extended = "Example: select _FUNC_('我是測試字符串') from src limit 1;\n"
                + "[\"我\", \"是\", \"測試\", \"字符串\"]")
public class IknalyzerSeg extends GenericUDF {
    private transient ObjectInspectorConverters.Converter[] converters;
    //用來存放停用詞的集合
    Set<String> stopWordSet = new HashSet<String>();

    @Override
    public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
        if (arguments.length < 1 || arguments.length > 2) {
            throw new UDFArgumentLengthException(
                    "The function AnsjSeg(str) takes 1 or 2 arguments.");
        }
        //讀入停用詞文件
        BufferedReader StopWordFileBr = null;
        try {
            StopWordFileBr = new BufferedReader(new InputStreamReader(new FileInputStream(new File("stopwords/baidu_stopwords.txt"))));
            //初如化停用詞集
            String stopWord = null;
            for(; (stopWord = StopWordFileBr.readLine()) != null;){
                stopWordSet.add(stopWord);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        converters = new ObjectInspectorConverters.Converter[arguments.length];
        converters[0] = ObjectInspectorConverters.getConverter(arguments[0], PrimitiveObjectInspectorFactory.writableStringObjectInspector);
        if (2 == arguments.length) {
            converters[1] = ObjectInspectorConverters.getConverter(arguments[1], PrimitiveObjectInspectorFactory.writableIntObjectInspector);
        }
        return ObjectInspectorFactory.getStandardListObjectInspector(PrimitiveObjectInspectorFactory.writableStringObjectInspector);

    }

    @Override
    public Object evaluate(DeferredObject[] arguments) throws HiveException {
        boolean filterStop = false;
        if (arguments[0].get() == null) {
            return null;
        }
        if (2 == arguments.length) {
            IntWritable filterParam = (IntWritable) converters[1].convert(arguments[1].get());
            if (1 == filterParam.get()) filterStop = true;
        }
        Text s = (Text) converters[0].convert(arguments[0].get());
        StringReader reader = new StringReader(s.toString());
        IKSegmenter iks = new IKSegmenter(reader, true);
        List<Text> list = new ArrayList<>();
        if (filterStop) {
            try {
                Lexeme lexeme;
                while ((lexeme = iks.next()) != null) {
                    if (!stopWordSet.contains(lexeme.getLexemeText())) {
                        list.add(new Text(lexeme.getLexemeText()));
                    }
                }
            } catch (IOException e) {
            }
        } else {
            try {
                Lexeme lexeme;
                while ((lexeme = iks.next()) != null) {
                    list.add(new Text(lexeme.getLexemeText()));
                }
            } catch (IOException e) {
            }
        }
        return list;
    }

    @Override
    public String getDisplayString(String[] children) {
        return "Usage: evaluate(String str)";
    }
}

第四步:編寫測試用例

GenericUDF 給我們提供了一些方法,這些方法可以用來構建測試需要的環境和參數,這樣我們就可以測試這些代碼了

@Test
public void testAnsjSegFunc() throws HiveException {
    AnsjSeg udf = new AnsjSeg();
    ObjectInspector valueOI0 = PrimitiveObjectInspectorFactory.javaStringObjectInspector;
    ObjectInspector valueOI1 = PrimitiveObjectInspectorFactory.javaIntObjectInspector;
    ObjectInspector[] init_args = {valueOI0, valueOI1};
    udf.initialize(init_args);

    Text str = new Text("我是測試字符串");

    GenericUDF.DeferredObject valueObj0 = new GenericUDF.DeferredJavaObject(str);
    GenericUDF.DeferredObject valueObj1 = new GenericUDF.DeferredJavaObject(0);
    GenericUDF.DeferredObject[] args = {valueObj0, valueObj1};
    ArrayList<Object> res = (ArrayList<Object>) udf.evaluate(args);
    System.out.println(res);
}


@Test
public void testIkSegFunc() throws HiveException {
    IknalyzerSeg udf = new IknalyzerSeg();
    ObjectInspector valueOI0 = PrimitiveObjectInspectorFactory.javaStringObjectInspector;
    ObjectInspector valueOI1 = PrimitiveObjectInspectorFactory.javaIntObjectInspector;
    ObjectInspector[] init_args = {valueOI0, valueOI1};
    udf.initialize(init_args);

    Text str = new Text("我是測試字符串");

    GenericUDF.DeferredObject valueObj0 = new GenericUDF.DeferredJavaObject(str);
    GenericUDF.DeferredObject valueObj1 = new GenericUDF.DeferredJavaObject(0);
    GenericUDF.DeferredObject[] args = {valueObj0, valueObj1};
    ArrayList<Object> res = (ArrayList<Object>) udf.evaluate(args);
    System.out.println(res);
}

我們看到加載停用詞沒有找到,但是整體還是跑起來了,因為讀取不到HDFS 上的文件

但是我們第二個樣例是不需要從HDFS 上加載停用詞信息,所以可以完美的測試運行

後來為了能在外部更新文件,我將其放在了HDFS 上,和AnsjSeg 中的代碼一樣

第五步:創建UDF 並使用

add jar /Users/liuwenqiang/workspace/code/idea/HiveUDF/target/HiveUDF-0.0.4.jar;
create temporary function ansjSeg as 'com.kingcall.bigdata.HiveUDF.AnsjSeg';
select ansjSeg("我是字符串,你是啥");
-- 開啟停用詞過濾
select ansjSeg("我是字符串,你是啥",1);
create temporary function ikSeg as 'com.kingcall.bigdata.HiveUDF.IknalyzerSeg';
select ikSeg("我是字符串,你是啥");
select ikSeg("我是字符串,你是啥",1);

上面方法的第二個參數,就是是否開啟停用詞過濾,我們使用ikSeg函數演示一下

下面我們嘗試獲取一下函數的描述信息

如果沒有寫的話,就是下面的這樣的

其它應用場景

通過編寫Hive UDF可以輕鬆幫我們實現大量常見需求,其它應該場景還有:

ip地址轉地區:將上報的用戶日誌中的ip欄位轉化為國家-省-市格式,便於做地域分布統計分析;

使用Hive SQL計算的標籤數據,不想編寫Spark程序,可以通過UDF在靜態代碼塊中初始化連接池,利用Hive啟動的並行MR任務,並行快速導入大量數據到codis中,應用於一些推薦業務;

還有其它sql實現相對複雜的任務,都可以編寫永久Hive UDF進行轉化;

總結

這一節我們學習了一個比較常見的UDF,通過實現GenericUDF 抽象類來實現,這一節的重點在於代碼的實現以及對GenericUDF類中方法的理解

上面的代碼實現上有一個問題,那就是關於停用詞的加載,就是我們能不能動態加載停用詞呢?


相關焦點

  • 編寫Hive的UDF(查詢平臺數據同時向mysql添加數據)
    ;修改配置:連接本地資料庫運行結果資料庫中本地測試成功開始打包項目放進集群進行測試把打包好的jar包改名為hive_udf3.jar放到集群裡NULL COMMENT '平臺名稱', `platform_version` varchar(10) DEFAULT NULL COMMENT '平臺版本', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='平臺信息表';進入hive
  • Fluent UDF【8】:編譯型UDF
    編譯/構建過程需要一個或多個UDF的源文件(例如myudf.c),並將它們編譯成對象文件(例如myudf.o或myudf.obj),之後將其構建成一個「共享庫」 (例如,libudf.dll)與目標文件。如果使用GUI方式編譯源文件,則當用戶單擊「Compiled UDF」對話框中的「Build」按鈕時,將執行編譯/構建過程。
  • 搞懂Hadoop、MapReduce、Hive、HBase、YARN及Spark的區別與聯繫
    03那什麼是hive呢hive是基於Hadoop的一個數據倉庫工具,用來進行數據提取、轉化、加載,可以存儲、查詢和分析存儲在Hive跑批:建表語句,要用文本格式,即Tsv格式,分割符可以自己定義:2)Spark 為我們提供了一個全面、統一的框架,用於管理各種有著不同性質(文本數據、圖表數據等)的數據集和數據源(批量數據或實時的流數據)的大數據處理的需求。
  • 海量新聞信息處理中的中文分詞算法研究
    我們知道,基於網絡輿情監控風險評估系統的算法是基於WEB文本挖掘一些基本的模型與算法:如TF-IDF模型,關聯規則的Apriori算法,監督學習中SVM算法等等。然而這些算法能用於中文文本挖掘的先決條件就是有一個良好中文的分詞模塊,所以中文分詞作為風險評估,網絡輿情的基礎工具,角色十分重要。
  • 創新工場兩篇論文入選ACL2020 中文分詞和詞性標註新模型性能創新高
    這兩篇論文各自提出了「鍵-值記憶神經網絡的中文分詞模型」和「基於雙通道注意力機制的分詞及詞性標註模型」,將外部知識(信息)創造性融入分詞及詞性標註模型,有效剔除了分詞「噪音」誤導,大幅度提升了分詞及詞性標註效果,將該領域近年來廣泛使用的數據集上的分數全部刷至新高。
  • 創新工場提出中文分詞和詞性標註模型,性能分別刷新五大數據集
    基於此,創新工場近日公布的兩篇論文各自提出了「鍵-值記憶神經網絡的中文分詞模型」和「基於雙通道注意力機制的分詞及詞性標註模型」,將外部知識(信息)創造性融入分詞及詞性標註模型,有效剔除了分詞「噪音」誤導,大幅度提升了分詞及詞性標註效果。
  • 創新工場提出中文分詞和詞性標註新模型可提升工業應用效率
    13日,記者從創新工場獲悉,其最新提出了中文分詞和詞性標註模型,可將外部知識(信息)融入分詞及詞性標註模型,剔除了分詞「噪音」誤導,提升了分詞及詞性標註效果。因此,在「鍵-值記憶神經網絡的中文分詞模型」的模型中,利用n元組(即一個由連續n個字組成的序列,比如「居民」是一個2元組,「生活水平」是一個4元組)提供的每個字的構詞能力,通過加(降)權重實現特定語境下的歧義消解。並通過非監督方法構建詞表,實現對特定領域的未標註文本的利用,進而提升對未登錄詞的識別。
  • 中文文本分類:你需要了解的10項關鍵內容
    中文文本分類最常用的特徵提取的方法就是分詞。區別於英文天然的存在空格符作為詞與詞之間的間隔標誌,中文文本中詞的提取必須通過基於序列預測等方法的分詞技術來實現。在提取了特徵值之後,再採用One-hot或TF-IDF等方法將每個樣本轉化為固定長度的特徵編碼作為分類算法的輸入。除了分詞,N-gram模型也完全值得你去嘗試。
  • 基於主題模型的網絡熱點新聞演化趨勢研究
    發現熱點新聞並對其演化趨勢進行挖掘可有利於媒體把握新聞風向和讀者喜好,並幫助用戶低成本、全方位地了解新聞事件的來龍去脈。媒體網站可通過實時獲取新聞並進行文本處理,運用聚類分析、時序主題挖掘等算法跟蹤了解熱點新聞事件的演化趨勢。本文結合相關挖掘技術,提供了一種基於主題模型的熱點新聞演化趨勢挖掘的流程設計,並結合具體的新聞事件進行分析。
  • Hanlp分詞之CRF中文詞法分析詳解
    這是另一套基於CRF的詞法分析系統,類似感知機詞法分析器,提供了完善的訓練與分析接口。CRF的效果比感知機稍好一些,然而訓練速度較慢,也不支持在線學習。默認模型訓練自OpenCorpus/pku98/199801.txt,隨hanlp 1.6.2以上版本發布。語料格式等與感知機詞法分析器相同,請先閱讀《感知機詞法分析器》。
  • 技術乾貨 | 如何做好文本關鍵詞提取?從三種算法說起
    在自然語言處理領域,處理海量的文本文件最關鍵的是要把用戶最關心的問題提取出來。而無論是對於長文本還是短文本,往往可以通過幾個關鍵詞窺探整個文本的主題思想。與此同時,不管是基於文本的推薦還是基於文本的搜索,對於文本關鍵詞的依賴也很大,關鍵詞提取的準確程度直接關係到推薦系統或者搜索系統的最終效果。因此,關鍵詞提取在文本挖掘領域是一個很重要的部分。
  • 基於百度LAC2.0的詞雲圖生成——各大分詞工具實戰比較
    百度方面宣稱,LAC在分詞、詞性、專名識別的整體準確率超過90%,以專名識別為例,其效果要比同類詞法分析工具提升10%以上。目前,百度已經發布了LAC2.0版本,之前的1.0版本我也寫過一篇博文加以探討,彼時的1.0版本還是融合在paddlehub中的一個模型,詳見利用百度超大規模預訓練模型進行分詞 一文。
  • 文本挖掘實操|用文本挖掘剖析54萬首詩歌,我發現了這些
    在這裡,筆者利用Jiayan(甲言)對這54餘萬首詩歌進行自動分詞,在結果中按照詞彙出現頻率從高到低進行排序,最終從語料庫中抽取若干有意義的高頻詞。其中,詞彙的長度從1到4。然而,電腦程式不能直接處理字符串形式的文本數據,所以筆者首當其衝的一個步驟就是將詩歌文本數據分詞,之後再「翻譯」為計算機可以處理的數據形式,這由一個名為「文本向量化」的操作來實現。先談分詞,它跟前面的高頻詞挖掘有聯繫,是後續所有分析任務的起始點。
  • 0730 知識點分享:現在分詞和過去分詞的用法
    現在分詞和過去分詞主要差別在於:現在分詞表示「主動和進行」,過去分詞表示「被動和完成」(不及物動詞的過去分詞不表示被動,只表示完成)。分詞可以有自己的狀語、賓語或邏輯主語等。1)分詞作狀語分詞在句子中作狀語,可以表示時間、條件、原因、結果、讓步、伴隨等。分詞做狀語時,它的邏輯主語與句子的主語一致。
  • 過去分詞、現在分詞不會用?最好懂得英語分詞用法講解,看完秒懂
    什麼過去分詞、現在分詞,都不明白。」,遇到一個語法專有名詞,立馬暈菜,要想不暈菜,你得把它搞明白!sleeping 就是現在分詞。I have learnt English for 5 years.我已經學習英語5年了。learnt 就是過去分詞。The floor was cleaned this morning.地板今早被清理乾淨了。我們最熟悉的粉刺用法:現在分詞用於「進行時」;過去分詞,用於「完成時」和「被動語態」。
  • 現在分詞和過去分詞作狀語的用法
    現在分詞(doing)和過去分詞(done)都有副詞性質,可以在句中充當狀語,表示時間、條件、原因、讓步、結果、方式或伴隨狀況等。一、分詞充當狀語時,分詞的邏輯主語一般要和句子主語保持一致。分詞充當狀語可視為狀語從句的簡化版,前提是狀語從句主語和主句主語一致。
  • 英語語法學習:非謂語動詞(現在分詞doing/過去分詞done的用法)
    非謂語動詞01分詞的構成分詞分為現在分詞和過去分詞兩種:現在分詞由「動詞+ing」構成;過去分詞由「動詞+ed」構成,但也有不規則形式。現在分詞有主動、進行之意;過去分詞有被動、完成之意。02分詞的句法功能① 作定語Do you know the girl standing under
  • Python文本處理工具都有哪些?
    從網頁上獲取文本數據之後,依據任務的不同,就需求進行根本的文本處理了,譬如關於英文來說,需求根本的tokenize,關於中文,則需求常見的中文分詞。那麼,Python文本處理東西都有哪些呢?今天就跟隨小編一起來了解下吧!
  • 現在分詞和過去分詞作定語的用法
    現在分詞(doing)和過去分詞(done)有形容詞性質,可以在句中充當定語。一、單個分詞充當前置定語現在分詞和被修飾詞之間一般是主動關係;過去分詞和被修飾詞之間一般是被動關係。speeches 歡迎辭a standing committee 常務委員會a decided step 決定性步驟a troubled place 是非之地a devoted friend 一位忠實的朋友二、分詞短語充當後置定語
  • 現在分詞與動名詞的區別及用法
    動詞可分四類:實義動詞 Hav系動詞 助動詞 情態動詞動詞有五種基本形式:動詞原形 第三人稱單數 現在分詞 過去式和過去分詞現在分詞是動詞的一種表現形式,常用來表示正在進行的動作,其構成:一,一般情況下,直接在動詞詞尾加—ing