Home Php C# Sql C C++ Javascript Python Java Go Android Git Linux Asp.net Django .net Node.js Ios Xcode Cocoa Iphone Mysql Tomcat Mongodb Bash Objective-c Scala Visual-studio Apache Elasticsearch Jar Eclipse Jquery Ruby-on-rails Ruby Rubygems Android-studio Spring Lua Sqlite Emacs Ubuntu Perl Docker Swift Amazon-web-services Svn Html Ajax Xml Java-ee Maven Intellij-idea Rvm Macos Unix Css Ipad Postgresql Css3 Json Windows-server Vue.js Typescript Oracle Hibernate Internet-explorer Github Tensorflow Laravel Symfony Redis Html5 Google-app-engine Nginx Firefox Sqlalchemy Lucene Erlang Flask Vim Solr Webview Facebook Zend-framework Virtualenv Nosql Ide Twitter Safari Flutter Bundle Phonegap Centos Sphinx Actionscript Tornado Register | Login | Edit Tags | New Questions | 繁体 | 简体


10 questions online user: 44

0
votes
answers
15 views
+10

JAXB vs Apache XMLBeans

Anyone can tell me which one is better (JAXB or Apache XMLBeans) taking in account the performance for files bigger than 10Mb?

0
votes
answers
13 views
+10

使用PHP和cURL調用API URL

1

我希望有人能幫助我。使用PHP和cURL調用API URL

我有一個使用這個URL的API調用。

https://192.168.11.234:4444/webconsole/APIController?reqxml=<Request><Login<Username>XXXXX</Username><Password>XXXXX></Password></Login><Get><User><Username>manager</Username></User></Get></Request> 

這工作正常,並按預期返回XML。

但是我試圖用PHP和cURL做同樣的事情。

我有捲曲

到目前爲止,我已經試過這種變化非常小經驗,但我沒有得到任何迴應。只有一個空白頁面。想知道是否有人可以幫助我。

<?php 
$input_xml = '<Request><Login><Username>XXXX</Username><Password>XXXX</Password></Login><Get><User></User></Get></Request>'; 
$url = "https://192.168.11.234:4444/webconsole/APIController"; 


     $ch = curl_init(); 
     curl_setopt($ch, CURLOPT_URL, $url); 

     curl_setopt($ch, CURLOPT_POSTFIELDS, 
        "reqxml=" . $input_xml); 
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
     curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 300); 
     $data = curl_exec($ch); 
     curl_close($ch); 


     $array_data = json_decode(json_encode(simplexml_load_string($data)), true); 

     print_r('<pre>'); 
     print_r($array_data); 
     print_r('</pre>'); 
?> 

我承認我沒有使用cURL很多,所以我可能會離開。

沙发
0
0

你明白了什麼,當你嘗試以下方法:

  • 的var_dump($的數據); ('Content-Type:application/xml'));}};

編輯: 哦,CURLOPT_POST =真

板凳
0
0

取出POSTFIEILDS線以及與此

curl_setopt($ch, CURLOPT_URL, $url."?reqxml=" . urlencode($input_xml)); 

這應該工作更換URL線。

地板
0
0

1)如果您的服務器不接受POST請求,然後刪除此行:

curl_setopt($ch, CURLOPT_POSTFIELDS, "reqxml=" . $input_xml); 

,並添加:

curl_setopt($ch, CURLOPT_URL, $url.'?reqxml='.urlencode($input_xml)); 

在GET請求發送數據。

2)設定正確的HTTP標頭:

$headers = [ 
    "Content-type: text/xml;charset="utf-8"", 
    "Accept: text/xml", 
    "Content-length: ".strlen($xml_data) 
]; 

curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 

3)要看到可能出現的錯誤,行$data = curl_exec($ch);前添加這些行:

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 
if (curl_error($ch)) { 
    echo 'error:' . curl_error($ch); 
} 

4)你也需要添加支票simplexml_load_string ,因爲失敗時返回false

if (simplexml_load_string($data) === false) { 
// do something 
} 

請讓我知道,如果我的回答幫助你。

4楼
0
0

我愛你們(或加侖) 這工作:

<?php 
$input_xml = '<Request><Login><Username>XXXXX</Username><Password>XXXXXX</Password></Login><Get><User></User></Get></Request>'; 
$url = "https://192.168.11.234:4444/webconsole/APIController"; 
$ch = curl_init(); 
$headers = [ 
    "Content-type: text/xml;charset="utf-8"", 
    "Accept: text/xml", 
    "Content-length: ".strlen($xml_data) 
]; 

curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 

     curl_setopt($ch, CURLOPT_URL, $url."?reqxml=" . urlencode($input_xml)); 
     curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
     curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 300); 
     curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 
      if (curl_error($ch)) { 
      echo 'error:' . curl_error($ch); 
      } 
     $data = curl_exec($ch); 
     var_dump($data); 
     curl_close($ch); 


     $array_data = json_decode(json_encode(simplexml_load_string($data)), true); 

     print_r('<pre>'); 
     print_r($array_data); 
     print_r('</pre>'); 
?> 

以爲我是接近,設定正確的標題,並改變:

curl_setopt($ch, CURLOPT_URL, $url); 

要:

curl_setopt($ch, CURLOPT_URL, $url."?reqxml=" . urlencode($input_xml)); 

是什麼幫助。非常感謝您的幫助!

+0

關閉CURLOPT_SSL_VERIFYPEER允許中間人(MITM)攻擊。 如果您的PHP安裝沒有最新的CA根證書包,請在curl網站下載並保存到您的服務器上: http://curl.haxx.se/docs/caextract .html 然後在你的php.ini文件中設置一個路徑,例如在Windows上: 'curl.cainfo = c: php cacert.pem' [(source)](http://php.net/manual/en/function.curl-setopt.php#110457) – camelsWriteInCamelCase

+0

誰的答案最有幫助,@ user3294740?請閱讀這篇文章[「我應該怎麼做,當有人回答我的問題?」](https://stackoverflow.com/help/someone-answers) – camelsWriteInCamelCase

8
votes
answers
10 views
+10

How to use XMLReader in PHP?

I have the following XML file, the file is rather large and i haven't been able to get simplexml to open and read the file so i'm trying XMLReader with no success in php

<?xml version="1.0" encoding="ISO-8859-1"?>
<products>
    <last_updated>2009-11-30 13:52:40</last_updated>
    <product>
        <element_1>foo</element_1>
        <element_2>foo</element_2>
        <element_3>foo</element_3>
        <element_4>foo</element_4>
    </product>
    <product>
        <element_1>bar</element_1>
        <element_2>bar</element_2>
        <element_3>bar</element_3>
        <element_4>bar</element_4>
    </product>
</products>

I've unfortunately not found a good tutorial on this for PHP and would love to see how I can get each element content to store in a database.

沙发
+40

The accepted answer gave me a good start, but brought in more classes and more processing than I would have liked; so this is my interpretation:

$xml_reader = new XMLReader;
$xml_reader->open($feed_url);

// move the pointer to the first product
while ($xml_reader->read() && $xml_reader->name != 'product');

// loop through the products
while ($xml_reader->name == 'product')
{
    // load the current xml element into simplexml and we’re off and running!
    $xml = simplexml_load_string($xml_reader->readOuterXML());

    // now you can use your simpleXML object ($xml).
    echo $xml->element_1;

    // move the pointer to the next product
    $xml_reader->next('product');
}

// don’t forget to close the file
$xml_reader->close();
板凳
+20

XMLReader is well documented on PHP site. This is a XML Pull Parser, which means it's used to iterate through nodes (or DOM Nodes) of given XML document. For example, you could go through the entire document you gave like this:

<?php
$reader = new XMLReader();
if (!$reader->open("data.xml"))
{
    die("Failed to open 'data.xml'");
}
while($reader->read())
{
    $node = $reader->expand();
    // process $node...
}
$reader->close();
?>

It is then up to you to decide how to deal with the node returned by XMLReader::expand().

how will you get it to move to the next node after it has finished processing one? – Shadi Almosri Dec 3 '09 at 2:09

關於XMLReader在php.net上有詳細記錄,我也不同意,這是我見過的最糟糕的文檔功能之一,我已經使用了php.net很長一段時間,這是我之前要解決這個問題的第一個地方在這裡問:) - Shadi Almosri 09年12月3日在2:10

我不確定你理解XMLReader :: read()從一個節點到另一個節點的方式。XMLReader類也使用libxml,這是一個眾所周知的庫,如果你想看看它也可用於PHP。 - Percutio 09年12月3日4:06

XMLReader被充分記錄的想法是無稽之談。問題是,如果你不知道從哪裡開始,它就不會告訴你任何地方:如果你不知道應該調用哪些方法,那麼給出一個類方法的清單是沒用的。 - xgretsch 2011年9月28日10:06

地板
+20
Simple example:

public function productsAction()
{
    $saveFileName = 'ceneo.xml';
    $filename = $this->path . $saveFileName;
    if(file_exists($filename)) {

    $reader = new XMLReader();
    $reader->open($filename);

    $countElements = 0;

    while($reader->read()) {
        if($reader->nodeType == XMLReader::ELEMENT) {
            $nodeName = $reader->name;
        }

        if($reader->nodeType == XMLReader::TEXT && !empty($nodeName)) {
            switch ($nodeName) {
                case 'id':
                    var_dump($reader->value);
                    break;
            }
        }

        if($reader->nodeType == XMLReader::END_ELEMENT && $reader->name == 'offer') {
            $countElements++;
        }
    }
    $reader->close();
    exit(print('<pre>') . var_dump($countElements));
    }
}
0
votes
answers
20 views
+10

Android佈局在另外兩個佈局的中間放置一個佈局

1

您好,我必須使用常規Android佈局創建UI,如下圖所示(附圖)。我得到了頁眉,頁腳和中間區域以及圖像視圖。 根據畫面:區域A和區域C是類似的高度(屏幕的20%)和圖像視圖應該總是在B區和C區的中間 enter image description hereAndroid佈局在另外兩個佈局的中間放置一個佈局

我的當前xml代碼是這樣被放置

<?xml version="1.0" encoding="utf-8"?> 
 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
 
    android:layout_width="match_parent" 
 
    android:layout_height="match_parent" 
 
    > 
 

 
    <LinearLayout 
 
     android:id="@+id/show_contact_bottomArea" 
 
     android:layout_width="match_parent" 
 
     android:layout_height="120dp" 
 
     android:orientation="vertical" 
 
     android:layout_alignParentBottom="true" 
 
     android:layout_alignParentLeft="true" 
 
     android:layout_alignParentStart="true"> 
 

 
    </LinearLayout> 
 

 
    <LinearLayout 
 
     android:id="@+id/show_contact_middleArea" 
 
     android:layout_width="match_parent" 
 
     android:layout_height="150dp" 
 
     android:orientation="vertical" 
 
     android:background="@color/grayContact" 
 
     android:layout_below="@+id/show_contact_headerArea" 
 
     android:layout_alignParentLeft="true" 
 
     android:layout_alignParentStart="true" 
 
     android:layout_above="@+id/show_contact_bottomArea"> 
 
     
 
    </LinearLayout> 
 

 
    <LinearLayout 
 
     android:id="@+id/show_contact_headerArea" 
 
     android:layout_width="match_parent" 
 
     android:layout_height="120dp" 
 
     android:orientation="vertical" 
 
     android:layout_alignParentTop="true" 
 
     android:layout_alignParentLeft="true" 
 
     android:layout_alignParentStart="true"></LinearLayout> 
 

 
    <ImageView 
 
     android:layout_width="150dp" 
 
     android:layout_height="150dp" 
 
     app:srcCompat="@drawable/common_google_signin_btn_icon_dark_focused" 
 
     android:id="@+id/imageView2" 
 
     android:layout_marginBottom="40dp" 
 
     android:layout_alignParentBottom="true" 
 
     android:layout_centerHorizontal="true" /> 
 

 
</RelativeLayout>

我給

marginBot tom =「40dp」

圖像視圖向上推,這不是一個好的做法。將圖像視圖放置在區域B和區域C邊界的中心的最佳方式是什麼?

也是目前我給

機器人:layout_height = 「120dp」

爲A區& B區的高度,但最好都應該是在屏幕上,怎樣的20%(每個)實現呢?

+0

使用的FrameLayout。它對這些種類或要求靈活 – Stallion

沙发
0
2

你可以給權重20%,至每一個ç(你希望出現在B的部分高度)。這樣他們將分別佔據頂部和底部的20%。將剩餘高度的60%分配給B

對於imageView,您可以將整個佈局放置在座標佈局中,並將錨點分配給頁腳。

她是代碼片段

<?xml version="1.0" encoding="utf-8"?> 
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 


    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
     xmlns:app="http://schemas.android.com/apk/res-auto" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:orientation="vertical" 
     android:weightSum="10"> 

     <LinearLayout 

      android:id="@+id/show_contact_bottomArea" 
      android:layout_width="match_parent" 
      android:layout_height="0dp" 
      android:layout_alignParentBottom="true" 
      android:layout_alignParentLeft="true" 
      android:layout_alignParentStart="true" 
      android:layout_weight="2" 
      android:background="@color/primary_light" 
      android:orientation="vertical"> 

     </LinearLayout> 

     <LinearLayout 
      android:id="@+id/show_contact_middleArea" 
      android:layout_width="match_parent" 
      android:layout_height="0dp" 
      android:layout_above="@+id/show_contact_bottomArea" 
      android:layout_alignParentLeft="true" 
      android:layout_alignParentStart="true" 
      android:layout_below="@+id/show_contact_headerArea" 
      android:layout_weight="6" 
      android:background="@color/holo_blue_light" 
      android:orientation="vertical"> 

     </LinearLayout> 

     <LinearLayout 
      android:id="@+id/show_contact_headerArea" 
      android:layout_width="match_parent" 
      android:layout_height="0dp" 
      android:layout_alignParentLeft="true" 
      android:layout_alignParentStart="true" 
      android:layout_alignParentTop="true" 
      android:layout_weight="2" 
      android:background="@color/primary" 
      android:orientation="vertical"></LinearLayout> 


    </LinearLayout> 

    <ImageView 
     android:id="@+id/imageView2" 
     android:layout_width="150dp" 
     android:layout_height="150dp" 
     android:layout_alignParentBottom="true" 
     android:layout_centerHorizontal="true" 
     android:layout_marginBottom="40dp" 
     app:layout_anchor="@+id/show_contact_headerArea" 
     app:layout_anchorGravity="center_horizontal|top" 
     app:srcCompat="@drawable/header_record" /> 


</android.support.design.widget.CoordinatorLayout> 

結果: - 我有彩色的不同部分具有不同的顏色代碼。

enter image description here

+0

謝謝你的答案,它的工作原理。是否可以根據區域C的高度設置圖像視圖的高度?我希望imageview的高度爲C區高度的一半? –

+0

找到C線性佈局的高度http://stackoverflow.com/questions/12068945/get-layout-height-and-width-at-run-time-android,然後動態設置它的高度http://stackoverflow.com/問題/ 3144940 /設置imageview的寬度和高度,以編程 –

板凳
0
0

使用重量爲給予和區的確切部分幀佈局 爲例如: 重量總和= 4具有在母體線性佈局,得到 區域A得到1- 區域B得到2- 區域C得到1-

B區後添加圖像查看與頂部 -

0
votes
answers
12 views
+10

無法添加CircularSeekBar到我的項目

1

嘿,無法添加CircularSeekBar到我的項目

我一直在嘗試了幾個小時添加this到我的項目,使燃油表。 我一直在做所有事情,因爲它在說明中顯示。但是我碰巧遇到了一些我無法解決的問題。 我按照指示粘貼了.java文件evidence,但我在這裏遇到2個問題。首先,「gradle」文件夾以紅色高亮顯示,相關的.java文件在其圖標中有一個紅色的J。我試圖搜索如何解決這些問題,但沒有爲我工作。 我不知道下一個問題是因爲以前的問題,但是當我嘗試在xml文件的父視圖中添加xmlns:app="http://schemas.android.com/apk/res/com.devadvance.circulartest" 時,我得到錯誤信息使用xmlns:app="http://schemas.android.com/apk/res-auto"來「自動」搜索自定義視圖,但它沒有沒有工作。所以我不能在活動中導入.java(它像它不存在的那樣),我不能在佈局文件中使用它。

請幫我試過在SO上搜索但我不能提前發現任何爲我工作。

入門Android開發人員在這裏:)

感謝。

+2

歡迎使用堆棧溢出。首先,你已經嘗試過尋找答案,這真是太棒了。並不是很多初學者都這麼做。你應該閱讀幫助部分,尤其是關於如何問的部分。特別是,我建議將問題源代碼添加到問題中,而不是鏈接圖片。另外,如果您有兩個可能無關的問題,請提出兩個問題。 –

+0

我得到它的工作。刪除.java文件圖標中的紅色J我刪除了我在finder中創建的文件夾,並使用Android studio +再次創建它們,因爲我的包名稱爲com.example。%MYNAME&。%APPNAME%它沒有'如果我把它放在com.example。%APPNAME%中,就不會起作用。所以我是一個白癡xD 任何方式感謝您的反饋。 – Wolo21

沙发
0
1

我曾嘗試使用您給出customseekbar在一個基本的Hello World應用程序。它的工作原理對我來說非常好

我看到你已經把com/devadvance/circulerseekbar/circularseekbar.java放在src文件夾裏,而不是main/java。所以它應該在src/main/java/com/devadvance/circulerseekbar/circularseekbar.java.

另外我發現你並不需要添加命名空間xmlns:app="http://schemas.android.com/apk/res/com.devadvance.circulartest而不是默認命名空間xmlns:app="http://schemas.android.com/apk/res-auto在xml文件中應該沒問題。

最後,不要忘記在customseekbar類中添加導入com.myapplication.R;以在customseekbar類中使用您的資源類R.

希望它有幫助,否則讓我知道!

enter image description here

0
votes
answers
21 views
+10

啓動其他活動時ImageView內存泄漏

0

我有一個名爲Test1的簡單活動。啓動其他活動時ImageView內存泄漏

這是佈局代碼。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:id="@+id/test" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    > 

    <ImageView 
     android:id="@+id/imageview1" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:adjustViewBounds="true" 
     android:src="@drawable/load" 
     android:scaleType="fitXY" /> 

</RelativeLayout> 

在我onDestory的方法,我鬆開mImageView資源和Android的分佈是,mImageView記憶真的被回收。

@Override 
    protected void onDestroy() { 
     super.onDestroy(); 
     releaseImageViewResource(mImageView); 
     layout.removeView(mImageView); 
     mImageView.setVisibility(View.GONE); 
     mImageView.setImageDrawable(null); 
     mImageView = null; 
    } 

enter image description here
但是當我啓動其他簡單的活動中,mImageView該內存不能被回收。爲什麼以及如何解決問題? enter image description here

+0

'但是當我開始其他簡單活動時?這是什麼意思?你的意思是,你是從ImageView開始的第一項活動,然後從該活動開始另一項活動?你能詳細說明一下嗎? – Henry

+0

完成那個你寫的onDestroy或者其他onDestroy()不會被調用的活動, – notTdar

沙发
0
0

爲了處理圖像,我建議你使用像GlidePicasso這樣的庫,他們會爲你處理所有的東西。 (內存泄漏,緩存等)

板凳
0
0

不確定你的意思是「開始其他簡單的活動」,但如果你要去應用程序內的另一個活動,那麼你當前的活動(與圖像視圖)應該暫停被摧毀。要麼當你去其他活動時調用finish(),要麼只需在onPause()方法中放入onDestroy()代碼

6
votes
answers
19 views
+10

Looping over elements inside an element in Flex

I have the following function in Flex 4:

protected function initEventHandlers():void
        {
            imageContainer.addEventListener(DragEvent.DRAG_ENTER, acceptDrag);
            imageContainer.addEventListener(DragEvent.DRAG_DROP, handleDrop);

            img_1.addEventListener(MouseEvent.MOUSE_DOWN, handleDrag);
            img_2.addEventListener(MouseEvent.MOUSE_DOWN, handleDrag);
            img_3.addEventListener(MouseEvent.MOUSE_DOWN, handleDrag);
            img_4.addEventListener(MouseEvent.MOUSE_DOWN, handleDrag);
        }

I didn't like the look of this code though. The four images are declared inside my application as follows:

<s:HGroup y="10" width="650" horizontalAlign="center" horizontalCenter="6">
        <s:Image width="80" height="80" source="images/1.jpg" id="img_1" />     
        <s:Image width="80" height="80" source="images/2.jpg" id="img_2" />
        <s:Image width="80" height="80" source="images/3.jpeg" id="img_3" />
        <s:Image width="80" height="80" source="images/4.jpg" id="img_4" />
</s:HGroup>

Isn't there a way to loop over each image in the hgroup and add the eventhandler?

Something like this:

for(image in hgroup) { 
    image.addEventlistener(MouseEvent.MOUSE_DOWN, handleDrag); 

}

 My teacher told me this isn't possible but in case of 10+ images, I can't imagine doing it for every image separately. There has to be a better way to do this, no?

Thanks in advance!

沙发
+60
+50

你的老師錯了!

給HGroup一個id(例如imageGroup)。

然後這樣做:

  var numElements:int = imageGroup.numElements; for(var i:int = 0; i&lt; numElements; i ++){var image:Image = imageGroup.getElementAt(i)as Image; if(image)image.addEventlistener(MouseEvent.MOUSE_DOWN,handleDrag); }  
     
			
        
0
votes
answers
28 views
+10

XML和HTML解析器選項NONET = 2048是做什麼或意味着什麼?

1

在Crystal標準庫中,HTMLXML解析器選項都具有NONET。這個選項做什麼修改XML.parse/XML.parse_html解析?XML和HTML解析器選項NONET = 2048是做什麼或意味着什麼?

沙发
0
4

它解析時禁用任何網絡連接,例如連接到互聯網以檢索XML DTD。

0
votes
answers
23 views
+10

在pre API 26上使用XML屬性paddingHorizo??ntal devies?

0

在API 26(Android O)及更高版本中引入了XML屬性android:paddingHorizontal?它是否有支持版本?我要求我的minSdkVersion要低的多是26在pre API 26上使用XML屬性paddingHorizo??ntal devies?

我的印象是Android Asset Packaging Tool 2.0 (AAPT2)下,這是被列入Android Studio中3,可能可能幫助了這一點。

從發行AAPT2發行說明:

版本2.16

aapt2鏈接...

版本的XML文件是更聰明,用一個小的一套規則降解特定更新屬性向後兼容版本。例如:android:paddingHorizo??ntal降級到android:paddingLeft和android:paddingRight。

但沒有知道如何使用AAPT2,我不會在那裏找到關於多少信息給你,我只是看到了它提...或者,如果我的請求,甚至有可能。 ..

任何幫助/答案非常感謝。

沙发
0
0

我認爲支持android:paddingHorizontal即使在API級別10中也是如此,如website所示。

+0

爲什麼我會在Android Studio XML編輯器上發出警告,說它只適用於API 26(O)?我有'targetSDKVersion'設置爲'26',我的minSdkVERSION設置爲'16'?還有爲什麼會有這麼多的站點解釋「paddingHorizo??ntal/Vertical」如何最終在API 26中出現?爲什麼這些博客/論壇/帖子會爲那些始終存在的東西狂歡? – Sakiboy

+0

我不知道爲什麼在API級別1中添加'padding' [屬性](https://developer.android.com/reference/android/R.attr.html#padding)時會有警告。也許你需要清理構建,然後重建你的項目。還要檢查SDK Manager中是否所有必需的組件都已成功安裝。 – Kvaibhav01

+0

當你向下滾動到特定的'paddingHorizo??ntal/Vertical'屬性時,你會看到文字說「在API級別26添加」,雖然。 – Sakiboy

117
votes
answers
28 views
+10

Best practices for searchable archive of thousands of documents (pdf and/or xml)

Revisiting a stalled project and looking for advice in modernizing thousands of "old" documents and making them available via web.

Documents exist in various formats, some obsolete: (.doc, PageMaker, hardcopy (OCR), PDF, etc.). Funds are available to migrate the documents into a 'modern' format, and many of the hardcopies have already been OCR'd into PDFs - we had originally assumed that PDF would be the final format but we're open to suggestions (XML?).

Once all docs are in a common format we would like to make their contents available and searchable via a web interface. We'd like the flexibility to return only portions (pages?) of the entire document where a search 'hit' is found (I believe Lucene/elasticsearch makes this possible?!?) Might it be more flexible if content was all XML? If so how/where to store the XML? Directly in database, or as discrete files in the filesystem? What about embedded images/graphs in the documents?

Curious how others might approach this. There is no "wrong" answer I'm just looking for as many inputs as possible to help us proceed.

Thanks for any advice.

up vote 113 down vote accepted favorite
沙发
+1130
+50

總結:我將推薦ElasticSearch,但讓我們解決問題,並討論如何實現它:

這有幾個部分:

  1. 從文檔中提取文本以使其可索引
  2. 將此文本作為全文搜索提供
  3. 返回文檔的突出顯示的片段
  4. 知道文檔中的哪些片段被發現允許分頁
  5. 返回完整的文檔

ElasticSearch可以提供什麼:

  1. ElasticSearch(如Solr)使用Tika從各種doc 格式中提取文本和元數據
  2. 很明顯,它提供了強大的全文搜索功能。它可以配置為使用適當的語言分析每個文檔,阻止,提高某些字段的相關性(例如標題比內容更重要),ngrams等,即標準Lucene的東西
  3. 它可以為每個搜索結果返回突出顯示的片段
  4. 它不知道你的文檔中出現這些片段的位置
  5. 它可以將原始文檔存儲為附件,也可以存儲和返回提取的文本。但它會返回整個文檔,而不是頁面。

您可以將整個文檔作為附件發送到ElasticSearch,然後您將獲得全文搜索。但關鍵點在於上面的(4)和(5):知道你在doc中的位置,以及返回doc的部分內容。

存儲單個頁面可能足以滿足您的“我在哪裡”的目的(儘管您可以同樣地進入段落級別),但是您希望它們按照在搜索結果中返回文檔的方式進行分組,即使搜索關鍵字出現在不同的頁面上。

首先是索引部分:將您的文檔存儲在ElasticSearch中:

  1. 使用Tika(或任何您熟悉的)從每個文檔中提取文本。將其保留為純文本或HTML,以保留一些格式。(忘記XML,不需要它)。
  2. 還提取每個文檔的元數據:標題,作者,章節,語言,日期等
  3. 將原始文檔存儲在文件系統中,並記錄路徑以便以後可以提供
  4. 在ElasticSearch中,索引一個“doc”doc,其中包含所有元數據,可能還包含章節列表
  5. 將每個頁面索引為“頁面”文檔,其中包含:

    • 父字段,其包含的“doc”文檔的ID(見“父-子關係”下方)
    • 文本
    • 頁碼
    • 也許是章節標題或編號
    • 您想要搜索的任何元數據

現在搜索。如何執行此操作取決於您希望如何按頁面顯示結果,或按文檔分組。

頁面結果很容易。此查詢返回匹配頁面的列表(每個頁面完整返回)以及頁面中突出顯示的片段列表:

curl -XGET 'http://127.0.0.1:9200/my_index/page/_search?pretty=1'  -d '
{
   "query" : {
      "text" : {
         "text" : "interesting keywords"
      }
   },
   "highlight" : {
      "fields" : {
         "text" : {}
      }
   }
}
'

顯示按“doc”分組的結果和文本中的突出顯示有點棘手。它不能通過單個查詢完成,但是一個小客戶端分組將幫助您。一種方法可能是:

步驟1:執行top-children-query以查找其子項(“page”)與查詢最匹配的父項(“doc”):

curl -XGET 'http://127.0.0.1:9200/my_index/doc/_search?pretty=1'  -d '
{
   "query" : {
      "top_children" : {
         "query" : {
            "text" : {
               "text" : "interesting keywords"
            }
         },
         "score" : "sum",
         "type" : "page",
         "factor" : "5"
      }
   }
}

第2步:從上面的查詢中收集“doc”ID並發出新查詢以從匹配的“頁面”文檔中獲取片段:

curl -XGET 'http://127.0.0.1:9200/my_index/page/_search?pretty=1'  -d '
{
   "query" : {
      "filtered" : {
         "query" : {
            "text" : {
               "text" : "interesting keywords"
            }
         },
         "filter" : {
            "terms" : {
               "doc_id" : [ 1,2,3],
            }
         }
      }
   },
   "highlight" : {
      "fields" : {
         "text" : {}
      }
   }
}
'

第3步:在您的應用中,按文檔對上述查詢的結果進行分組並顯示它們。

使用第二個查詢的搜索結果,您已經擁有了可以顯示的頁面的全文。要移至下一頁,您只需搜索它:

curl -XGET 'http://127.0.0.1:9200/my_index/page/_search?pretty=1'  -d '
{
   "query" : {
      "constant_score" : {
         "filter" : {
            "and" : [
               {
                  "term" : {
                     "doc_id" : 1
                  }
               },
               {
                  "term" : {
                     "page" : 2
                  }
               }
            ]
         }
      }
   },
   "size" : 1
}
'

或者,給“頁面”文檔一個由$doc_id _ $page_num(例如123_2)組成的ID,然後您可以只檢索該頁面:

curl -XGET 'http://127.0.0.1:9200/my_index/page/123_2

親子關係:

通常,在ES(和大多數NoSQL解決方案)中,每個doc / object都是獨立的 - 沒有真正的關係。通過在“doc”和“page”之間建立父子關係,ElasticSearch確保子文檔(即“頁面”)與父文檔(“doc”)存儲在同一個分片上。

這使您可以運行top-children-query,它將根據“pages”的內容找到最匹配的“doc”。

好吧,我會說:“DrTech為總統!” ;-)很棒的答案!希望我能更多地投票。謝謝! - Meltemi 12年2月2日14:28

:)有趣的是,畢竟我的名字是克林頓:) - DrTech 12月2日在22:03

你不知道怎麼去索引PDF的每個“頁面”? - Meltemi 2012年6月14日22:51

Poppler工具poppler.freedesktop.org默認在大多數Linux發行版上都可用,非常快速且非常好。 - DrTech 2012年6月15日9:21

如果按頁面拆分,那麼您也可能無法找到分隔多個頁面的短語,不是嗎? - 結束於2015年4月27日凌晨4點21分

+20

我已經構建並維護了一個索引和搜索70k + PDF文檔的應用程序。我發現必須從PDF中提取純文本,將內容存儲在SQL中並使用Lucene索引SQL表。否則,表現太可怕了。

將內容存儲在數據庫中有什麼好處?是不是更容易提取內容(假設你不只是使用Solr並跳過手動處理),索引它,並丟棄純文本內容? - 戴夫牛頓2012年6月1日18:12

好吧......我不得不回去查看代碼。這就是我正在做的事情。首先,我必須說,我們有一個單獨的索引服務器來處理這個功能。以下是過程:1)從內容服務器上的PDF中提取文本2)使用類似的目錄/文件名將文本存儲在.txt文件中。3)索引文本文件。在搜索時,我們能夠根據文件路徑/命名將結果與原始PDF相關聯 - Josh Siok Jun於2012年1月1日18:26

我認為在這裡使用關係數據庫沒有任何好處。@Dave,一次更正,你不丟棄原始文本內容,你使用搜索引擎(Solr,ES,...)來索引和存儲它。然後,在搜索結果中,您只需顯示原始文件的鏈接。 - Marko Bonaci 12年4月4日11:36

我們這樣做有兩個原因。首先,整體索引時間更快。其次,數據庫中存在與每個文檔對應的相關數據,因此以這種方式構建完整索引更簡單。 - Josh Siok 6月4日在13:01

+20

使用SunspotRSolr等,它處理大多數主要文檔格式。他們使用Solr / Lucene。

在這種情況下,PDF格式的優缺點是什麼?在這個階段,我們可以選擇任何一種方式。我認為PDF最初可能更容易創建,但可能更難維護和“服務”?!?不知道。尋求建議。 - Meltemi 6月1日在18:26

@Meltemi我不知道PDF如何更難以服務; 文件是文件。XML文件需要格式化,您需要在所有格式之間進行轉換為xml。 - 戴夫牛頓2012年6月1日18:29

文件是文件,但我們希望一次只“提供”整個文檔的一部分。所以我想我們可以將每個PDF分解成數百個較小的PDF,它們開始變得笨拙。想知道XML是否可以使這一過程變得更加容易?!?也許不是。 - Meltemi 12年1月1日20:57

@Meltemi完全取決於; 在不知道具體要求的情況下,很難說。XML DB有點失寵。內容仍然需要格式化/轉換,這可能是您想要的簡單或複雜。根據您的需要,從原始源到XML的轉換可能是微不足道的,或者基本上是不可能的。可能最好使用大數據解決方案並完全刪除應用程序級別的文件 - 一個hBase行可以有數百萬個列,每個列包含一個段落或其他,每行都是一個單獨的doc。大量的解決方案。 - 戴夫牛頓2012年6月1日21:08

@ D.Newton - “大量的解決方案”。那就是我問這些問題的原因。我正在尋找想法。不嘗試挑邊。至於“要求”,它們與可能性,複雜性和成本相關聯。基本上我所知道的是,我們希望用戶能夠查詢所有這些報告,以及文檔中是否存在包含“點擊”的“點擊”部分。並且,從那裡,我相信我們希望用戶能夠繼續翻閱文檔。但不要下載整件事。希望有意義嗎?!? - Meltemi 12年2月2日0:00